Merge pull request #58 from mipt-npm/dev
0.2.0 release
This commit is contained in:
commit
6912f26291
.gitignoreCHANGELOG.mdbuild.gradle.kts
dataforge-context
api
build.gradle.ktssrc
commonMain/kotlin/hep/dataforge
context
AbstractPlugin.ktContext.ktContextBuilder.ktFactory.ktGlobal.ktNamed.ktPlugin.ktPluginManager.ktPluginRepository.ktPluginTag.ktresolve.kt
properties
provider
commonTest/kotlin/hep/dataforge/context
jsMain/kotlin/hep/dataforge
jvmMain/kotlin/hep/dataforge
dataforge-data
api
build.gradle.ktssrc
commonMain/kotlin/hep/dataforge/data
Action.ktCoroutineMonitor.ktData.ktDataFilter.ktDataNode.ktGoal.ktGroupRule.ktMapAction.ktReduceAction.ktSplitAction.ktdataCast.kt
jsMain/kotlin/hep/dataforge/data
jvmMain/kotlin/hep/dataforge/data
nativeMain/kotlin/hep/dataforge/data
dataforge-io
api
build.gradle.ktsdataforge-io-yaml
src
commonMain/kotlin/hep/dataforge/io
BinaryMetaFormat.ktConsumer.ktEnvelope.ktEnvelopeBuilder.ktEnvelopeFormat.ktEnvelopeParts.ktIOFormat.ktIOPlugin.ktJsonMetaFormat.ktMetaFormat.ktResponder.ktTaggedEnvelopeFormat.ktTaglessEnvelopeFormat.kt
functions
ioMisc.ktcommonTest/kotlin/hep/dataforge/io
jvmMain/kotlin/hep/dataforge/io
jvmTest/kotlin/hep/dataforge/io/tcp
dataforge-meta
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,5 +6,4 @@ out/
|
|||||||
build/
|
build/
|
||||||
|
|
||||||
|
|
||||||
!gradle-wrapper.jar
|
!gradle-wrapper.jar
|
||||||
gradle.properties
|
|
39
CHANGELOG.md
Normal file
39
CHANGELOG.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Security
|
||||||
|
## [0.2.0]
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Context content resolution refactor
|
||||||
|
- Kotlin 1.4.10 (build tools 0.6.0)
|
||||||
|
- Empty query in Name is null instead of ""
|
||||||
|
- Provider provides an empty map instead of error by default
|
||||||
|
- Hidden delegates hierarchy in favor of stdlib properties
|
||||||
|
- Removed io depdendency from `dataforge-output`. Replaced Output by Appendable.
|
||||||
|
- Configurable is no longer MutableItemProvider. All functionality moved to Scheme.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- Context activation API
|
||||||
|
- TextRenderer
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Functional server prototype
|
||||||
|
- `dataforge-output` module
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Global context CoroutineScope resolution
|
||||||
|
- Library mode compliance
|
||||||
|
|
||||||
|
### Security
|
@ -1,27 +1,24 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
val toolsVersion = "0.5.0"
|
id("ru.mipt.npm.project")
|
||||||
id("scientifik.mpp") version toolsVersion apply false
|
|
||||||
id("scientifik.jvm") version toolsVersion apply false
|
|
||||||
id("scientifik.publish") version toolsVersion apply false
|
|
||||||
id("org.jetbrains.dokka") version "0.10.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.1.8")
|
val dataforgeVersion by extra("0.2.0")
|
||||||
|
|
||||||
val bintrayRepo by extra("dataforge")
|
val bintrayRepo by extra("dataforge")
|
||||||
val githubProject by extra("dataforge-core")
|
val githubProject by extra("dataforge-core")
|
||||||
|
val spaceRepo by extra("https://maven.jetbrains.space/mipt-npm/p/df/maven")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "hep.dataforge"
|
group = "hep.dataforge"
|
||||||
version = dataforgeVersion
|
version = dataforgeVersion
|
||||||
|
|
||||||
|
apply<org.jetbrains.dokka.gradle.DokkaPlugin>()
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply(plugin = "scientifik.publish")
|
apply(plugin = "ru.mipt.npm.publish")
|
||||||
apply(plugin = "org.jetbrains.dokka")
|
|
||||||
}
|
}
|
334
dataforge-context/api/dataforge-context.api
Normal file
334
dataforge-context/api/dataforge-context.api
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
public abstract class hep/dataforge/context/AbstractPlugin : hep/dataforge/context/Plugin {
|
||||||
|
public fun <init> ()V
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Meta;)V
|
||||||
|
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 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;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/AbstractPluginKt {
|
||||||
|
public static final fun toMap (Ljava/util/Collection;)Ljava/util/Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/ClassLoaderPlugin : hep/dataforge/context/AbstractPlugin {
|
||||||
|
public static final field Companion Lhep/dataforge/context/ClassLoaderPlugin$Companion;
|
||||||
|
public fun <init> (Ljava/lang/ClassLoader;)V
|
||||||
|
public fun getTag ()Lhep/dataforge/context/PluginTag;
|
||||||
|
public final fun services (Lkotlin/reflect/KClass;)Lkotlin/sequences/Sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/ClassLoaderPlugin$Companion {
|
||||||
|
public final fun getDEFAULT ()Lhep/dataforge/context/ClassLoaderPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
public fun <init> ()V
|
||||||
|
public fun <init> (Lhep/dataforge/context/Context;Ljava/lang/String;)V
|
||||||
|
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
|
||||||
|
public static synthetic fun plugin$default (Lhep/dataforge/context/ContextBuilder;Lhep/dataforge/context/PluginFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
|
||||||
|
public static synthetic fun plugin$default (Lhep/dataforge/context/ContextBuilder;Lhep/dataforge/context/PluginTag;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
|
||||||
|
public static synthetic fun plugin$default (Lhep/dataforge/context/ContextBuilder;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
|
||||||
|
public final fun properties (Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun setName (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/context/Factory {
|
||||||
|
public abstract fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/Factory$DefaultImpls {
|
||||||
|
public static synthetic fun invoke$default (Lhep/dataforge/context/Factory;Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;ILjava/lang/Object;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/Global : hep/dataforge/context/Context {
|
||||||
|
public static final field INSTANCE Lhep/dataforge/context/Global;
|
||||||
|
public fun close ()V
|
||||||
|
public final fun context (Ljava/lang/String;Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Context;
|
||||||
|
public static synthetic fun context$default (Lhep/dataforge/context/Global;Ljava/lang/String;Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/context/Context;
|
||||||
|
public final fun getContext (Ljava/lang/String;)Lhep/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/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 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 detach ()V
|
||||||
|
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public abstract fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public abstract fun getTag ()Lhep/dataforge/context/PluginTag;
|
||||||
|
public abstract fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/Plugin$Companion {
|
||||||
|
public static final field TARGET Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/context/PluginFactory : hep/dataforge/context/Factory {
|
||||||
|
public static final field Companion Lhep/dataforge/context/PluginFactory$Companion;
|
||||||
|
public static final field TYPE Ljava/lang/String;
|
||||||
|
public abstract fun getTag ()Lhep/dataforge/context/PluginTag;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/PluginFactory$Companion {
|
||||||
|
public static final field TYPE Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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;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;
|
||||||
|
public final fun get (Lhep/dataforge/context/PluginTag;Z)Lhep/dataforge/context/Plugin;
|
||||||
|
public final fun get (Lkotlin/reflect/KClass;Lhep/dataforge/context/PluginTag;Z)Ljava/lang/Object;
|
||||||
|
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;
|
||||||
|
public final fun load (Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;)Lhep/dataforge/context/Plugin;
|
||||||
|
public final fun load (Lhep/dataforge/context/PluginFactory;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Plugin;
|
||||||
|
public static synthetic fun load$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/context/Plugin;
|
||||||
|
public final fun remove (Lhep/dataforge/context/Plugin;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/PluginTag : hep/dataforge/meta/MetaRepr {
|
||||||
|
public static final field Companion Lhep/dataforge/context/PluginTag$Companion;
|
||||||
|
public static final field DATAFORGE_GROUP Ljava/lang/String;
|
||||||
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public final fun component1 ()Ljava/lang/String;
|
||||||
|
public final fun component2 ()Ljava/lang/String;
|
||||||
|
public final fun component3 ()Ljava/lang/String;
|
||||||
|
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lhep/dataforge/context/PluginTag;
|
||||||
|
public static synthetic fun copy$default (Lhep/dataforge/context/PluginTag;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lhep/dataforge/context/PluginTag;
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getGroup ()Ljava/lang/String;
|
||||||
|
public final fun getName ()Ljava/lang/String;
|
||||||
|
public final fun getVersion ()Ljava/lang/String;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public final fun matches (Lhep/dataforge/context/PluginTag;)Z
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/PluginTag$Companion {
|
||||||
|
public final fun fromString (Ljava/lang/String;)Lhep/dataforge/context/PluginTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/context/ResolveKt {
|
||||||
|
public static final fun gather (Lhep/dataforge/context/Context;Ljava/lang/String;Lkotlin/reflect/KClass;Z)Ljava/util/Map;
|
||||||
|
public static synthetic fun gather$default (Lhep/dataforge/context/Context;Ljava/lang/String;Lkotlin/reflect/KClass;ZILjava/lang/Object;)Ljava/util/Map;
|
||||||
|
public static final fun gatherInSequence (Lhep/dataforge/context/Context;Ljava/lang/String;Lkotlin/reflect/KClass;Z)Lkotlin/sequences/Sequence;
|
||||||
|
public static synthetic fun gatherInSequence$default (Lhep/dataforge/context/Context;Ljava/lang/String;Lkotlin/reflect/KClass;ZILjava/lang/Object;)Lkotlin/sequences/Sequence;
|
||||||
|
public static final fun getValues (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence;
|
||||||
|
public static final fun resolve (Lhep/dataforge/context/Context;Ljava/lang/String;Lhep/dataforge/names/Name;Lkotlin/reflect/KClass;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface annotation class hep/dataforge/descriptors/Attribute : java/lang/annotation/Annotation {
|
||||||
|
public abstract fun key ()Ljava/lang/String;
|
||||||
|
public abstract fun value ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface annotation class hep/dataforge/descriptors/Attributes : java/lang/annotation/Annotation {
|
||||||
|
public abstract fun attrs ()[Lhep/dataforge/descriptors/Attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface annotation class hep/dataforge/descriptors/ItemDef : java/lang/annotation/Annotation {
|
||||||
|
public abstract fun info ()Ljava/lang/String;
|
||||||
|
public abstract fun multiple ()Z
|
||||||
|
public abstract fun required ()Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface annotation class hep/dataforge/descriptors/ValueDef : java/lang/annotation/Annotation {
|
||||||
|
public abstract fun allowed ()[Ljava/lang/String;
|
||||||
|
public abstract fun def ()Ljava/lang/String;
|
||||||
|
public abstract fun enumeration ()Ljava/lang/Class;
|
||||||
|
public abstract fun type ()[Lhep/dataforge/values/ValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/properties/ConfigProperty : hep/dataforge/properties/Property {
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Config;Lhep/dataforge/names/Name;Lhep/dataforge/meta/transformations/MetaConverter;)V
|
||||||
|
public final fun getConfig ()Lhep/dataforge/meta/Config;
|
||||||
|
public final fun getConverter ()Lhep/dataforge/meta/transformations/MetaConverter;
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getValue ()Ljava/lang/Object;
|
||||||
|
public fun onChange (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public fun removeChangeListener (Ljava/lang/Object;)V
|
||||||
|
public fun setValue (Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/properties/Property {
|
||||||
|
public abstract fun getValue ()Ljava/lang/Object;
|
||||||
|
public abstract fun onChange (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public abstract fun removeChangeListener (Ljava/lang/Object;)V
|
||||||
|
public abstract fun setValue (Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/properties/Property$DefaultImpls {
|
||||||
|
public static synthetic fun onChange$default (Lhep/dataforge/properties/Property;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
|
||||||
|
public static synthetic fun removeChangeListener$default (Lhep/dataforge/properties/Property;Ljava/lang/Object;ILjava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/properties/PropertyKt {
|
||||||
|
public static final fun bind (Lhep/dataforge/properties/Property;Lhep/dataforge/properties/Property;)V
|
||||||
|
public static final fun mirror (Lhep/dataforge/properties/Property;Lhep/dataforge/properties/Property;Lkotlinx/coroutines/CoroutineScope;)V
|
||||||
|
public static final fun toFlow (Lhep/dataforge/properties/Property;)Lkotlinx/coroutines/flow/StateFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/provider/DfTypeKt {
|
||||||
|
public static final fun getDfType (Lkotlin/reflect/KClass;)Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/provider/Path : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
|
||||||
|
public static final field Companion Lhep/dataforge/provider/Path$Companion;
|
||||||
|
public static final field PATH_SEGMENT_SEPARATOR Ljava/lang/String;
|
||||||
|
public static final synthetic fun box-impl (Ljava/util/List;)Lhep/dataforge/provider/Path;
|
||||||
|
public static fun constructor-impl (Ljava/util/List;)Ljava/util/List;
|
||||||
|
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
|
||||||
|
public fun iterator ()Ljava/util/Iterator;
|
||||||
|
public static fun iterator-impl (Ljava/util/List;)Ljava/util/Iterator;
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
public static fun toString-impl (Ljava/util/List;)Ljava/lang/String;
|
||||||
|
public final synthetic fun unbox-impl ()Ljava/util/List;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/provider/Path$Companion {
|
||||||
|
public final fun parse-IN54j3k (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 final class hep/dataforge/provider/PathToken {
|
||||||
|
public static final field Companion Lhep/dataforge/provider/PathToken$Companion;
|
||||||
|
public static final field TARGET_SEPARATOR Ljava/lang/String;
|
||||||
|
public fun <init> (Lhep/dataforge/names/Name;Ljava/lang/String;)V
|
||||||
|
public synthetic fun <init> (Lhep/dataforge/names/Name;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public final fun component1 ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun component2 ()Ljava/lang/String;
|
||||||
|
public final fun copy (Lhep/dataforge/names/Name;Ljava/lang/String;)Lhep/dataforge/provider/PathToken;
|
||||||
|
public static synthetic fun copy$default (Lhep/dataforge/provider/PathToken;Lhep/dataforge/names/Name;Ljava/lang/String;ILjava/lang/Object;)Lhep/dataforge/provider/PathToken;
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getTarget ()Ljava/lang/String;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/provider/PathToken$Companion {
|
||||||
|
public final fun parse (Ljava/lang/String;)Lhep/dataforge/provider/PathToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/provider/Provider {
|
||||||
|
public abstract fun content (Ljava/lang/String;)Ljava/util/Map;
|
||||||
|
public abstract fun getDefaultChainTarget ()Ljava/lang/String;
|
||||||
|
public abstract fun getDefaultTarget ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/provider/Provider$DefaultImpls {
|
||||||
|
public static fun content (Lhep/dataforge/provider/Provider;Ljava/lang/String;)Ljava/util/Map;
|
||||||
|
public static fun getDefaultChainTarget (Lhep/dataforge/provider/Provider;)Ljava/lang/String;
|
||||||
|
public static fun getDefaultTarget (Lhep/dataforge/provider/Provider;)Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
|
@ -1,32 +1,30 @@
|
|||||||
import scientifik.useCoroutines
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("ru.mipt.npm.mpp")
|
||||||
|
id("ru.mipt.npm.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "Context and provider definitions"
|
description = "Context and provider definitions"
|
||||||
|
|
||||||
|
kscience {
|
||||||
useCoroutines()
|
useCoroutines()
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-meta"))
|
api(project(":dataforge-meta"))
|
||||||
api("io.github.microutils:kotlin-logging-common:1.7.9")
|
api("io.github.microutils:kotlin-logging:1.9.0-dev-npm-2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmMain by getting {
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(kotlin("reflect"))
|
api(kotlin("reflect"))
|
||||||
api("io.github.microutils:kotlin-logging:1.7.9")
|
|
||||||
api("ch.qos.logback:logback-classic:1.2.3")
|
api("ch.qos.logback:logback-classic:1.2.3")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("io.github.microutils:kotlin-logging-js:1.7.9")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import kotlin.properties.ReadOnlyProperty
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plugin {
|
public abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plugin {
|
||||||
private var _context: Context? = null
|
private var _context: Context? = null
|
||||||
private val dependencies = ArrayList<PluginFactory<*>>()
|
private val dependencies = ArrayList<PluginFactory<*>>()
|
||||||
|
|
||||||
@ -30,11 +30,9 @@ abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plugin {
|
|||||||
dependencies.add(factory)
|
dependencies.add(factory)
|
||||||
return PluginDependencyDelegate(factory.type)
|
return PluginDependencyDelegate(factory.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun provideTop(target: String): Map<Name, Any> = emptyMap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Named> Collection<T>.toMap(): Map<Name, T> = associate { it.name to it }
|
public fun <T : Named> Collection<T>.toMap(): Map<Name, T> = associate { it.name to it }
|
||||||
|
|
||||||
private class PluginDependencyDelegate<P : Plugin>(val type: KClass<out P>) : ReadOnlyProperty<AbstractPlugin, P> {
|
private class PluginDependencyDelegate<P : Plugin>(val type: KClass<out P>) : ReadOnlyProperty<AbstractPlugin, P> {
|
||||||
override fun getValue(thisRef: AbstractPlugin, property: KProperty<*>): P {
|
override fun getValue(thisRef: AbstractPlugin, property: KProperty<*>): P {
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package hep.dataforge.context
|
package hep.dataforge.context
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Laminate
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaRepr
|
||||||
|
import hep.dataforge.meta.sequence
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.provider.Provider
|
import hep.dataforge.provider.Provider
|
||||||
import hep.dataforge.provider.top
|
|
||||||
import hep.dataforge.values.Value
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import mu.KLogger
|
import mu.KLogger
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.jvm.JvmName
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
|
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
|
||||||
@ -24,73 +23,52 @@ import kotlin.jvm.JvmName
|
|||||||
* different plugins with the same interface in different contexts in the hierarchy. The usual behaviour is to use nearest one, but it could
|
* different plugins with the same interface in different contexts in the hierarchy. The usual behaviour is to use nearest one, but it could
|
||||||
* be overridden by plugin implementation.
|
* be overridden by plugin implementation.
|
||||||
*
|
*
|
||||||
* Since plugins could contain mutable state, context has two states: active and inactive. No changes are allowed to active context.
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
*/
|
||||||
open class Context(
|
public open class Context(
|
||||||
final override val name: Name,
|
final override val name: Name,
|
||||||
val parent: Context? = Global
|
public val parent: Context?,
|
||||||
|
meta: Meta,
|
||||||
|
plugins: Set<Plugin> = emptySet(),
|
||||||
) : Named, MetaRepr, Provider, CoroutineScope {
|
) : Named, MetaRepr, Provider, CoroutineScope {
|
||||||
|
|
||||||
private val config = Config()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context properties. Working as substitute for environment variables
|
* Context properties. Working as substitute for environment variables
|
||||||
*/
|
*/
|
||||||
val properties: Meta = if (parent == null) {
|
private val properties: Laminate = if (parent == null) {
|
||||||
config
|
Laminate(meta)
|
||||||
} else {
|
} else {
|
||||||
Laminate(config, parent.properties)
|
Laminate(meta, parent.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context logger
|
* Context logger
|
||||||
*/
|
*/
|
||||||
val logger: KLogger = KotlinLogging.logger(name.toString())
|
public val logger: KLogger = KotlinLogging.logger(name.toString())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [PluginManager] for current context
|
* A [PluginManager] for current context
|
||||||
*/
|
*/
|
||||||
val plugins: PluginManager by lazy { PluginManager(this) }
|
public val plugins: PluginManager by lazy { PluginManager(this, plugins)}
|
||||||
|
|
||||||
private val activators = HashSet<Any>()
|
override val defaultTarget: String get() = Plugin.TARGET
|
||||||
|
|
||||||
/**
|
public fun content(target: String, inherit: Boolean): Map<Name, Any> {
|
||||||
* Defines if context is used in any kind of active computations. Active context properties and plugins could not be changed
|
return if (inherit) {
|
||||||
*/
|
when (target) {
|
||||||
val isActive: Boolean = activators.isNotEmpty()
|
PROPERTY_TARGET -> properties.sequence().toMap()
|
||||||
|
Plugin.TARGET -> plugins.list(true).associateBy { it.name }
|
||||||
override val defaultTarget: String get() = Plugin.PLUGIN_TARGET
|
else -> emptyMap()
|
||||||
|
}
|
||||||
override fun provideTop(target: String): Map<Name, Any> {
|
} else {
|
||||||
return when (target) {
|
when (target) {
|
||||||
Value.TYPE -> properties.sequence().toMap()
|
PROPERTY_TARGET -> properties.layers.firstOrNull()?.sequence()?.toMap() ?: emptyMap()
|
||||||
Plugin.PLUGIN_TARGET -> plugins.sequence(true).associateBy { it.name }
|
Plugin.TARGET -> plugins.list(false).associateBy { it.name }
|
||||||
else -> emptyMap()
|
else -> emptyMap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun content(target: String): Map<Name, Any> = content(target, true)
|
||||||
* Mark context as active and used by [activator]
|
|
||||||
*/
|
|
||||||
fun activate(activator: Any) {
|
|
||||||
activators.add(activator)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark context unused by [activator]
|
|
||||||
*/
|
|
||||||
fun deactivate(activator: Any) {
|
|
||||||
activators.remove(activator)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the properties of the context. If active, throw an exception
|
|
||||||
*/
|
|
||||||
fun configure(action: Config.() -> Unit) {
|
|
||||||
if (isActive) error("Can't configure active context")
|
|
||||||
config.action()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext by lazy {
|
override val coroutineContext: CoroutineContext by lazy {
|
||||||
(parent ?: Global).coroutineContext.let { parenContext ->
|
(parent ?: Global).coroutineContext.let { parenContext ->
|
||||||
@ -101,81 +79,35 @@ open class Context(
|
|||||||
/**
|
/**
|
||||||
* Detach all plugins and terminate context
|
* Detach all plugins and terminate context
|
||||||
*/
|
*/
|
||||||
open fun close() {
|
public open fun close() {
|
||||||
if (isActive) error("Can't close active context")
|
|
||||||
//detach all plugins
|
//detach all plugins
|
||||||
plugins.forEach { it.detach() }
|
plugins.forEach { it.detach() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
"parent" to parent?.name
|
"parent" to parent?.name
|
||||||
"properties" put properties.seal()
|
"properties" put properties.layers.firstOrNull()
|
||||||
"plugins" put plugins.map { it.toMeta() }
|
"plugins" put plugins.map { it.toMeta() }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.content(target: String): Map<Name, Any> = content<Any>(target)
|
public companion object {
|
||||||
|
public const val PROPERTY_TARGET: String = "context.property"
|
||||||
/**
|
|
||||||
* A map of all objects provided by plugins with given target and type
|
|
||||||
*/
|
|
||||||
@JvmName("typedContent")
|
|
||||||
inline fun <reified T : Any> Context.content(target: String): Map<Name, T> =
|
|
||||||
plugins.flatMap { plugin ->
|
|
||||||
plugin.top<T>(target).entries.map { (plugin.name + it.key) to it.value }
|
|
||||||
}.associate { it }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A global root context. Closing [Global] terminates the framework.
|
|
||||||
*/
|
|
||||||
object Global : Context("GLOBAL".asName(), null) {
|
|
||||||
/**
|
|
||||||
* Closing all contexts
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
override fun close() {
|
|
||||||
logger.info { "Shutting down GLOBAL" }
|
|
||||||
for (ctx in contextRegistry.values) {
|
|
||||||
ctx.close()
|
|
||||||
}
|
|
||||||
super.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val contextRegistry = HashMap<String, Context>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get previously built context
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
fun getContext(name: String): Context? {
|
|
||||||
return contextRegistry[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun context(name: String, parent: Context = this, block: ContextBuilder.() -> Unit = {}): Context =
|
|
||||||
ContextBuilder(name, parent).apply(block).build()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface for something that encapsulated in context
|
* The interface for something that encapsulated in context
|
||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
|
||||||
* @version $Id: $Id
|
|
||||||
*/
|
*/
|
||||||
interface ContextAware {
|
public interface ContextAware {
|
||||||
/**
|
/**
|
||||||
* Get context for this object
|
* Get context for this object
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
val context: Context
|
public val context: Context
|
||||||
|
|
||||||
val logger: KLogger
|
public val logger: KLogger
|
||||||
get() = if (this is Named) {
|
get() = if (this is Named) {
|
||||||
KotlinLogging.logger((context.name + this.name).toString())
|
KotlinLogging.logger((context.name + this.name).toString())
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,44 +1,44 @@
|
|||||||
package hep.dataforge.context
|
package hep.dataforge.context
|
||||||
|
|
||||||
import hep.dataforge.meta.DFBuilder
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.MetaBuilder
|
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience builder for context
|
* A convenience builder for context
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class ContextBuilder(var name: String = "@anonymous", val parent: Context = Global) {
|
public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") {
|
||||||
private val plugins = ArrayList<Plugin>()
|
private val plugins = HashSet<Plugin>()
|
||||||
private var meta = MetaBuilder()
|
private var meta = MetaBuilder()
|
||||||
|
|
||||||
fun properties(action: MetaBuilder.() -> Unit) {
|
public fun properties(action: MetaBuilder.() -> Unit) {
|
||||||
meta.action()
|
meta.action()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun plugin(plugin: Plugin) {
|
public fun plugin(plugin: Plugin) {
|
||||||
plugins.add(plugin)
|
plugins.add(plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun plugin(tag: PluginTag, action: MetaBuilder.() -> Unit = {}) {
|
@OptIn(DFExperimental::class)
|
||||||
plugins.add(PluginRepository.fetch(tag, Meta(action)))
|
private fun findPluginFactory(tag: PluginTag): PluginFactory<*> =
|
||||||
|
parent.gatherInSequence<PluginFactory<*>>(PluginFactory.TYPE).values
|
||||||
|
.find { it.tag.matches(tag) } ?: error("Can't resolve plugin factory for $tag")
|
||||||
|
|
||||||
|
public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) {
|
||||||
|
val factory = findPluginFactory(tag)
|
||||||
|
val plugin = factory.invoke(Meta(metaBuilder), parent)
|
||||||
|
plugins.add(plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun plugin(builder: PluginFactory<*>, action: MetaBuilder.() -> Unit = {}) {
|
public fun plugin(builder: PluginFactory<*>, action: MetaBuilder.() -> Unit = {}) {
|
||||||
plugins.add(builder.invoke(Meta(action)))
|
plugins.add(builder.invoke(Meta(action)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun plugin(name: String, group: String = "", version: String = "", action: MetaBuilder.() -> Unit = {}) {
|
public fun plugin(name: String, group: String = "", version: String = "", action: MetaBuilder.() -> Unit = {}) {
|
||||||
plugin(PluginTag(name, group, version), action)
|
plugin(PluginTag(name, group, version), action)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): Context {
|
public fun build(): Context {
|
||||||
return Context(name.toName(), parent).apply {
|
return Context(name.toName(), parent, meta.seal(), plugins)
|
||||||
this@ContextBuilder.plugins.forEach {
|
|
||||||
plugins.load(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,6 @@ package hep.dataforge.context
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
|
||||||
interface Factory<out T : Any> {
|
public interface Factory<out T : Any> {
|
||||||
operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T
|
public operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package hep.dataforge.context
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.names.asName
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.native.concurrent.ThreadLocal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A global root context. Closing [Global] terminates the framework.
|
||||||
|
*/
|
||||||
|
@ThreadLocal
|
||||||
|
public object Global : Context("GLOBAL".asName(), null, Meta.EMPTY) {
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext = GlobalScope.coroutineContext + SupervisorJob()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closing all contexts
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
override fun close() {
|
||||||
|
logger.info { "Shutting down GLOBAL" }
|
||||||
|
for (ctx in contextRegistry.values) {
|
||||||
|
ctx.close()
|
||||||
|
}
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val contextRegistry = HashMap<String, Context>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get previously built context
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public fun getContext(name: String): Context? {
|
||||||
|
return contextRegistry[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun context(name: String, parent: Context = this, block: ContextBuilder.() -> Unit = {}): Context =
|
||||||
|
ContextBuilder(parent, name).apply(block).build().also {
|
||||||
|
contextRegistry[name] = it
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,16 +24,14 @@ import hep.dataforge.names.isEmpty
|
|||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
interface Named {
|
public interface Named {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of this object instance
|
* The name of this object instance
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
val name: Name
|
public val name: Name
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of given object. If object is Named its name is used,
|
* Get the name of given object. If object is Named its name is used,
|
||||||
@ -42,7 +40,7 @@ interface Named {
|
|||||||
* @param obj
|
* @param obj
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun nameOf(obj: Any): Name {
|
public fun nameOf(obj: Any): Name {
|
||||||
return if (obj is Named) {
|
return if (obj is Named) {
|
||||||
obj.name
|
obj.name
|
||||||
} else {
|
} else {
|
||||||
@ -56,5 +54,4 @@ interface Named {
|
|||||||
* Check if this object has an empty name and therefore is anonymous.
|
* Check if this object has an empty name and therefore is anonymous.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
val Named.isAnonymous: Boolean
|
public val Named.isAnonymous: Boolean get() = this.name.isEmpty()
|
||||||
get() = this.name.isEmpty()
|
|
||||||
|
@ -1,43 +1,34 @@
|
|||||||
package hep.dataforge.context
|
package hep.dataforge.context
|
||||||
|
|
||||||
|
import hep.dataforge.context.Plugin.Companion.TARGET
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaRepr
|
import hep.dataforge.meta.MetaRepr
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Provider
|
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.
|
* The interface to define a Context plugin. A plugin stores all runtime features of a context.
|
||||||
* The plugin is by default configurable and a Provider (both features could be ignored).
|
* The plugin is by default configurable and a Provider (both features could be ignored).
|
||||||
* The plugin must in most cases have an empty constructor in order to be able to load it from library.
|
* The plugin must in most cases have an empty constructor in order to be able to load it from library.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* The plugin lifecycle is the following:
|
* The plugin lifecycle is the following:
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* create - configure - attach - detach - destroy
|
* create - configure - attach - detach - destroy
|
||||||
*
|
|
||||||
*
|
|
||||||
* Configuration of attached plugin is possible for a context which is not in a runtime mode, but it is not recommended.
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
*/
|
||||||
interface Plugin : Named, ContextAware, Provider, MetaRepr {
|
@Type(TARGET)
|
||||||
|
public interface Plugin : Named, ContextAware, Provider, MetaRepr {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get tag for this plugin
|
* Get tag for this plugin
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
val tag: PluginTag
|
public val tag: PluginTag
|
||||||
|
|
||||||
val meta: Meta
|
public val meta: Meta
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of this plugin ignoring version and group
|
* The name of this plugin ignoring version and group
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
override val name: Name get() = tag.name.toName()
|
override val name: Name get() = tag.name.toName()
|
||||||
|
|
||||||
@ -45,25 +36,21 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
|
|||||||
* Plugin dependencies which are required to attach this plugin. Plugin
|
* Plugin dependencies which are required to attach this plugin. Plugin
|
||||||
* dependencies must be initialized and enabled in the Context before this
|
* dependencies must be initialized and enabled in the Context before this
|
||||||
* plugin is enabled.
|
* plugin is enabled.
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
fun dependsOn(): Collection<PluginFactory<*>>
|
public fun dependsOn(): Collection<PluginFactory<*>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start this plugin and attach registration info to the context. This method
|
* Start this plugin and attach registration info to the context. This method
|
||||||
* should be called only via PluginManager to avoid dependency issues.
|
* should be called only via PluginManager to avoid dependency issues.
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
*/
|
*/
|
||||||
fun attach(context: Context)
|
public fun attach(context: Context)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop this plugin and remove registration info from context and other
|
* Stop this plugin and remove registration info from context and other
|
||||||
* plugins. This method should be called only via PluginManager to avoid
|
* plugins. This method should be called only via PluginManager to avoid
|
||||||
* dependency issues.
|
* dependency issues.
|
||||||
*/
|
*/
|
||||||
fun detach()
|
public fun detach()
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
"context" put context.name.toString()
|
"context" put context.name.toString()
|
||||||
@ -72,9 +59,8 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
|
|||||||
"meta" put meta
|
"meta" put meta
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
public const val TARGET: String = "plugin"
|
||||||
const val PLUGIN_TARGET = "plugin"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,42 +2,62 @@ package hep.dataforge.context
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaBuilder
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
import hep.dataforge.provider.Type
|
||||||
import kotlin.reflect.KClass
|
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.
|
* The manager for plugin system. Should monitor plugin dependencies and locks.
|
||||||
*
|
*
|
||||||
* @property context A context for this plugin manager
|
* @property context A context for this plugin manager
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> {
|
public class PluginManager(override val context: Context, plugins: Set<Plugin>) : ContextAware, Iterable<Plugin> {
|
||||||
|
|
||||||
|
//TODO refactor to read-only container
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of loaded plugins
|
* A set of loaded plugins
|
||||||
*/
|
*/
|
||||||
private val plugins = HashSet<Plugin>()
|
private val plugins: HashSet<Plugin> = HashSet(plugins)
|
||||||
|
|
||||||
|
init {
|
||||||
|
plugins.forEach { it.attach(context) }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [PluginManager] of parent context if it is present
|
* A [PluginManager] of parent context if it is present
|
||||||
*/
|
*/
|
||||||
private val parent: PluginManager? = context.parent?.plugins
|
private val parent: PluginManager? = context.parent?.plugins
|
||||||
|
|
||||||
|
/**
|
||||||
fun sequence(recursive: Boolean): Sequence<Plugin> {
|
* List plugins stored in this [PluginManager]. If [inherit] is true, include parent plugins as well
|
||||||
return if (recursive && parent != null) {
|
*/
|
||||||
plugins.asSequence() + parent.sequence(true)
|
public fun list(inherit: Boolean): Collection<Plugin> {
|
||||||
|
return if (inherit && parent != null) {
|
||||||
|
plugins + parent.list(true)
|
||||||
} else {
|
} else {
|
||||||
plugins.asSequence()
|
plugins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get existing plugin or return null if not present. Only first matching plugin is returned.
|
* Get existing plugin or return null if not present. Only first matching plugin is returned.
|
||||||
* @param recursive search for parent [PluginManager] plugins
|
* @param inherit search for parent [PluginManager] plugins
|
||||||
* @param predicate condition for the plugin
|
* @param predicate condition for the plugin
|
||||||
*/
|
*/
|
||||||
fun find(recursive: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = sequence(recursive).find(predicate)
|
public fun find(inherit: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? =
|
||||||
|
list(inherit).find(predicate)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a loaded plugin via its tag
|
* Find a loaded plugin via its tag
|
||||||
@ -45,8 +65,8 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
* @param tag
|
* @param tag
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
operator fun get(tag: PluginTag, recursive: Boolean = true): Plugin? = find(recursive) { tag.matches(it.tag) }
|
public operator fun get(tag: PluginTag, inherit: Boolean = true): Plugin? =
|
||||||
|
find(inherit) { tag.matches(it.tag) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a loaded plugin via its class. This method does not check if the result is unique and just returns first
|
* Find a loaded plugin via its class. This method does not check if the result is unique and just returns first
|
||||||
@ -60,13 +80,13 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
operator fun <T : Any> get(type: KClass<out T>, tag: PluginTag? = null, recursive: Boolean = true): T? =
|
public operator fun <T : Any> get(type: KClass<out T>, tag: PluginTag? = null, recursive: Boolean = true): T? =
|
||||||
find(recursive) { type.isInstance(it) && (tag == null || tag.matches(it.tag)) } as T?
|
find(recursive) { type.isInstance(it) && (tag == null || tag.matches(it.tag)) } as T?
|
||||||
|
|
||||||
inline operator fun <reified T : Any> get(tag: PluginTag? = null, recursive: Boolean = true): T? =
|
public inline operator fun <reified T : Any> get(tag: PluginTag? = null, recursive: Boolean = true): T? =
|
||||||
get(T::class, tag, recursive)
|
get(T::class, tag, recursive)
|
||||||
|
|
||||||
inline operator fun <reified T : Plugin> get(factory: PluginFactory<T>, recursive: Boolean = true): T? =
|
public inline operator fun <reified T : Plugin> get(factory: PluginFactory<T>, recursive: Boolean = true): T? =
|
||||||
get(factory.type, factory.tag, recursive)
|
get(factory.type, factory.tag, recursive)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,11 +96,9 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
* @param plugin
|
* @param plugin
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun <T : Plugin> load(plugin: T): T {
|
public fun <T : Plugin> load(plugin: T): T {
|
||||||
if (context.isActive) error("Can't load plugin into active context")
|
|
||||||
|
|
||||||
if (get(plugin::class, plugin.tag, recursive = false) != null) {
|
if (get(plugin::class, plugin.tag, recursive = false) != null) {
|
||||||
error("Plugin of type ${plugin::class} already exists in ${context.name}")
|
error("Plugin with tag ${plugin.tag} already exists in ${context.name}")
|
||||||
} else {
|
} else {
|
||||||
for (tag in plugin.dependsOn()) {
|
for (tag in plugin.dependsOn()) {
|
||||||
fetch(tag, true)
|
fetch(tag, true)
|
||||||
@ -96,18 +114,16 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
/**
|
/**
|
||||||
* Load a plugin using its factory
|
* Load a plugin using its factory
|
||||||
*/
|
*/
|
||||||
fun <T : Plugin> load(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY): T =
|
public fun <T : Plugin> load(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY): T =
|
||||||
load(factory(meta, context))
|
load(factory(meta, context))
|
||||||
|
|
||||||
fun <T : Plugin> load(factory: PluginFactory<T>, metaBuilder: MetaBuilder.() -> Unit): T =
|
public fun <T : Plugin> load(factory: PluginFactory<T>, metaBuilder: MetaBuilder.() -> Unit): T =
|
||||||
load(factory, Meta(metaBuilder))
|
load(factory, Meta(metaBuilder))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a plugin from [PluginManager]
|
* Remove a plugin from [PluginManager]
|
||||||
*/
|
*/
|
||||||
fun remove(plugin: Plugin) {
|
public fun remove(plugin: Plugin) {
|
||||||
if (context.isActive) error("Can't remove plugin from active context")
|
|
||||||
|
|
||||||
if (plugins.contains(plugin)) {
|
if (plugins.contains(plugin)) {
|
||||||
logger.info { "Removing plugin ${plugin.name} from ${context.name}" }
|
logger.info { "Removing plugin ${plugin.name} from ${context.name}" }
|
||||||
plugin.detach()
|
plugin.detach()
|
||||||
@ -117,9 +133,8 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an existing plugin with given meta or load new one using provided factory
|
* Get an existing plugin with given meta or load new one using provided factory
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T {
|
public fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T {
|
||||||
val loaded = get(factory.type, factory.tag, recursive)
|
val loaded = get(factory.type, factory.tag, recursive)
|
||||||
return when {
|
return when {
|
||||||
loaded == null -> load(factory(meta, context))
|
loaded == null -> load(factory(meta, context))
|
||||||
@ -128,10 +143,10 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Plugin> fetch(
|
public fun <T : Plugin> fetch(
|
||||||
factory: PluginFactory<T>,
|
factory: PluginFactory<T>,
|
||||||
recursive: Boolean = true,
|
recursive: Boolean = true,
|
||||||
metaBuilder: MetaBuilder.() -> Unit
|
metaBuilder: MetaBuilder.() -> Unit,
|
||||||
): T = fetch(factory, recursive, Meta(metaBuilder))
|
): T = fetch(factory, recursive, Meta(metaBuilder))
|
||||||
|
|
||||||
override fun iterator(): Iterator<Plugin> = plugins.iterator()
|
override fun iterator(): Iterator<Plugin> = plugins.iterator()
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package hep.dataforge.context
|
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
interface PluginFactory<T : Plugin> : Factory<T> {
|
|
||||||
val tag: PluginTag
|
|
||||||
val type: KClass<out T>
|
|
||||||
}
|
|
||||||
|
|
||||||
expect object PluginRepository {
|
|
||||||
|
|
||||||
fun register(factory: PluginFactory<*>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List plugins available in the repository
|
|
||||||
*/
|
|
||||||
fun list(): Sequence<PluginFactory<*>>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch specific plugin and instantiate it with given meta
|
|
||||||
*/
|
|
||||||
fun PluginRepository.fetch(tag: PluginTag, meta: Meta = Meta.EMPTY): Plugin =
|
|
||||||
list().find { it.tag.matches(tag) }?.invoke(meta = meta)
|
|
||||||
?: error("Plugin with tag $tag not found in the repository")
|
|
||||||
|
|
||||||
fun <T : Plugin> PluginRepository.register(
|
|
||||||
tag: PluginTag,
|
|
||||||
type: KClass<out T>,
|
|
||||||
constructor: (Context, Meta) -> T
|
|
||||||
): PluginFactory<T> {
|
|
||||||
val factory = object : PluginFactory<T> {
|
|
||||||
override val tag: PluginTag = tag
|
|
||||||
override val type: KClass<out T> = type
|
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): T = constructor(context, meta)
|
|
||||||
|
|
||||||
}
|
|
||||||
register(factory)
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Plugin> PluginRepository.register(tag: PluginTag, noinline constructor: (Context, Meta) -> T) =
|
|
||||||
register(tag, T::class, constructor)
|
|
||||||
|
|
||||||
fun PluginRepository.register(plugin: Plugin) = register(plugin.tag, plugin::class) { _, _ -> plugin }
|
|
@ -2,7 +2,6 @@ package hep.dataforge.context
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaRepr
|
import hep.dataforge.meta.MetaRepr
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tag which contains information about name, group and version of some
|
* The tag which contains information about name, group and version of some
|
||||||
@ -10,7 +9,7 @@ import hep.dataforge.meta.buildMeta
|
|||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
data class PluginTag(
|
public data class PluginTag(
|
||||||
val name: String,
|
val name: String,
|
||||||
val group: String = "",
|
val group: String = "",
|
||||||
val version: String = ""
|
val version: String = ""
|
||||||
@ -22,7 +21,7 @@ data class PluginTag(
|
|||||||
* @param otherTag
|
* @param otherTag
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun matches(otherTag: PluginTag): Boolean {
|
public fun matches(otherTag: PluginTag): Boolean {
|
||||||
return matchesName(otherTag) && matchesGroup(otherTag)
|
return matchesName(otherTag) && matchesGroup(otherTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,9 +41,9 @@ data class PluginTag(
|
|||||||
"version" put version
|
"version" put version
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
|
||||||
const val DATAFORGE_GROUP = "hep.dataforge"
|
public const val DATAFORGE_GROUP: String = "hep.dataforge"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build new PluginTag from standard string representation
|
* Build new PluginTag from standard string representation
|
||||||
@ -52,7 +51,7 @@ data class PluginTag(
|
|||||||
* @param tag
|
* @param tag
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun fromString(tag: String): PluginTag {
|
public fun fromString(tag: String): PluginTag {
|
||||||
val sepIndex = tag.indexOf(":")
|
val sepIndex = tag.indexOf(":")
|
||||||
return if (sepIndex >= 0) {
|
return if (sepIndex >= 0) {
|
||||||
PluginTag(group = tag.substring(0, sepIndex), name = tag.substring(sepIndex + 1))
|
PluginTag(group = tag.substring(0, sepIndex), name = tag.substring(sepIndex + 1))
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package hep.dataforge.context
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.plus
|
||||||
|
import hep.dataforge.provider.Provider
|
||||||
|
import hep.dataforge.provider.top
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.cast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a specific element in top level elements of the provider and attempt to cast it to the given type
|
||||||
|
*/
|
||||||
|
private fun <T : Any> Provider.provide(target: String, name: Name, type: KClass<out T>): T? {
|
||||||
|
return content(target)[name]?.let { type.cast(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a top level object with given [target] and [name] in a [Context] own scope or its plugins.
|
||||||
|
*/
|
||||||
|
public fun <T : Any> Context.resolve(target: String, name: Name, type: KClass<out T>): T? {
|
||||||
|
//Try searching for plugin an context property
|
||||||
|
provide(target, name, type)?.let { return it }
|
||||||
|
val pluginContent = plugins.mapNotNull { it.provide(target, name, type) }
|
||||||
|
return if (pluginContent.isEmpty()) {
|
||||||
|
parent?.resolve<T>(target, name, type)
|
||||||
|
} else {
|
||||||
|
pluginContent.single() // throws error in case of name/type conflicts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a top level object with given [target] and [name] in a [Context] own scope or its plugins.
|
||||||
|
*/
|
||||||
|
public inline fun <reified T : Any> Context.resolve(target: String, name: Name): T? =
|
||||||
|
resolve(target, name, T::class)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather a map of all top-level objects with given [target] from context plugins.
|
||||||
|
* Content from plugins is prefixed by plugin name so name conflicts are impossible
|
||||||
|
* This operation could be slow in case of large number of plugins
|
||||||
|
*/
|
||||||
|
public fun <T : Any> Context.gather(
|
||||||
|
target: String,
|
||||||
|
type: KClass<out T>,
|
||||||
|
inherit: Boolean = true,
|
||||||
|
): Map<Name, T> = buildMap {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inherit) {
|
||||||
|
parent?.gather(target, type, inherit)?.forEach {
|
||||||
|
//put all values from parent if they are not conflicting
|
||||||
|
if (!containsKey(it.key)) {
|
||||||
|
put(it.key, it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun <reified T : Any> Context.gather(target: String, inherit: Boolean = true): Map<Name, T> =
|
||||||
|
gather(target, T::class, inherit)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather all content from context itself and its plugins in a form of sequence of name-value pairs. Ignores name conflicts.
|
||||||
|
*
|
||||||
|
* Adds parent context sequence as well if [inherit] is true
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public fun <T : Any> Context.gatherInSequence(
|
||||||
|
target: String,
|
||||||
|
type: KClass<out T>,
|
||||||
|
inherit: Boolean = true,
|
||||||
|
): Sequence<Map.Entry<Name, T>> = sequence {
|
||||||
|
yieldAll(top(target, type).entries)
|
||||||
|
plugins.forEach { plugin ->
|
||||||
|
yieldAll(plugin.top(target, type).mapKeys { plugin.name + it.key }.entries)
|
||||||
|
}
|
||||||
|
if (inherit) {
|
||||||
|
parent?.gather(target, type, inherit)?.let {
|
||||||
|
yieldAll(it.entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
public inline fun <reified T : Any> Context.gatherInSequence(
|
||||||
|
target: String,
|
||||||
|
inherit: Boolean = true,
|
||||||
|
): Sequence<Map.Entry<Name, T>> = gatherInSequence(target, T::class, inherit)
|
||||||
|
|
||||||
|
public val <T> Sequence<Map.Entry<Name, T>>.values: Sequence<T> get() = map { it.value }
|
@ -0,0 +1,33 @@
|
|||||||
|
package hep.dataforge.properties
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.transformations.MetaConverter
|
||||||
|
import hep.dataforge.meta.transformations.nullableItemToObject
|
||||||
|
import hep.dataforge.meta.transformations.nullableObjectToMetaItem
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
public class ConfigProperty<T : Any>(
|
||||||
|
public val config: Config,
|
||||||
|
public val name: Name,
|
||||||
|
public val converter: MetaConverter<T>,
|
||||||
|
) : Property<T?> {
|
||||||
|
|
||||||
|
override var value: T?
|
||||||
|
get() = converter.nullableItemToObject(config[name])
|
||||||
|
set(value) {
|
||||||
|
config.setItem(name,converter.nullableObjectToMetaItem(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChange(owner: Any?, callback: (T?) -> Unit) {
|
||||||
|
config.onChange(owner) { name, oldItem, newItem ->
|
||||||
|
if (name == this.name && oldItem != newItem) callback(converter.nullableItemToObject(newItem))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeChangeListener(owner: Any?) {
|
||||||
|
config.removeListener(owner)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package hep.dataforge.properties
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
public interface Property<T> {
|
||||||
|
public var value: T
|
||||||
|
|
||||||
|
public fun onChange(owner: Any? = null, callback: (T) -> Unit)
|
||||||
|
public fun removeChangeListener(owner: Any? = null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
public fun <T> Property<T>.toFlow(): StateFlow<T> = MutableStateFlow(value).also { stateFlow ->
|
||||||
|
onChange {
|
||||||
|
stateFlow.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reflect all changes in the [source] property onto this property
|
||||||
|
*
|
||||||
|
* @return a mirroring job
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public fun <T> Property<T>.mirror(source: Property<T>, scope: CoroutineScope) {
|
||||||
|
source.onChange(this) {
|
||||||
|
this.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bi-directional connection between properties
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public fun <T> Property<T>.bind(other: Property<T>) {
|
||||||
|
onChange(other) {
|
||||||
|
other.value = it
|
||||||
|
}
|
||||||
|
other.onChange {
|
||||||
|
this.value = it
|
||||||
|
}
|
||||||
|
}
|
@ -26,25 +26,25 @@ import hep.dataforge.names.toName
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
* @version $Id: $Id
|
* @version $Id: $Id
|
||||||
*/
|
*/
|
||||||
inline class Path(val tokens: List<PathToken>) : Iterable<PathToken> {
|
public inline class Path(public val tokens: List<PathToken>) : Iterable<PathToken> {
|
||||||
|
|
||||||
val head: PathToken? get() = tokens.firstOrNull()
|
public val head: PathToken? get() = tokens.firstOrNull()
|
||||||
|
|
||||||
val length: Int get() = tokens.size
|
public val length: Int get() = tokens.size
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns non-empty optional containing the chain without first segment in case of chain path.
|
* Returns non-empty optional containing the chain without first segment in case of chain path.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
val tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1))
|
public val tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1))
|
||||||
|
|
||||||
override fun iterator(): Iterator<PathToken> = tokens.iterator()
|
override fun iterator(): Iterator<PathToken> = tokens.iterator()
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val PATH_SEGMENT_SEPARATOR = "/"
|
public const val PATH_SEGMENT_SEPARATOR: String = "/"
|
||||||
|
|
||||||
fun parse(path: String): Path {
|
public fun parse(path: String): Path {
|
||||||
val head = path.substringBefore(PATH_SEGMENT_SEPARATOR)
|
val head = path.substringBefore(PATH_SEGMENT_SEPARATOR)
|
||||||
val tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
|
val tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
|
||||||
return PathToken.parse(head).toPath() + parse(tail)
|
return PathToken.parse(head).toPath() + parse(tail)
|
||||||
@ -52,18 +52,18 @@ inline class Path(val tokens: List<PathToken>) : Iterable<PathToken> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Path.plus(path: Path) = Path(this.tokens + path.tokens)
|
public operator fun Path.plus(path: Path): Path = Path(this.tokens + path.tokens)
|
||||||
|
|
||||||
data class PathToken(val name: Name, val target: String? = null) {
|
public data class PathToken(val name: Name, val target: String? = null) {
|
||||||
override fun toString(): String = if (target == null) {
|
override fun toString(): String = if (target == null) {
|
||||||
name.toString()
|
name.toString()
|
||||||
} else {
|
} else {
|
||||||
"$target$TARGET_SEPARATOR$name"
|
"$target$TARGET_SEPARATOR$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val TARGET_SEPARATOR = "::"
|
public const val TARGET_SEPARATOR: String = "::"
|
||||||
fun parse(token: String): PathToken {
|
public fun parse(token: String): PathToken {
|
||||||
val target = token.substringBefore(TARGET_SEPARATOR, "")
|
val target = token.substringBefore(TARGET_SEPARATOR, "")
|
||||||
val name = token.substringAfter(TARGET_SEPARATOR).toName()
|
val name = token.substringAfter(TARGET_SEPARATOR).toName()
|
||||||
if (target.contains("[")) TODO("target separators in queries are not supported")
|
if (target.contains("[")) TODO("target separators in queries are not supported")
|
||||||
@ -72,4 +72,4 @@ data class PathToken(val name: Name, val target: String? = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PathToken.toPath() = Path(listOf(this))
|
public fun PathToken.toPath(): Path = Path(listOf(this))
|
||||||
|
@ -16,41 +16,37 @@
|
|||||||
package hep.dataforge.provider
|
package hep.dataforge.provider
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.toName
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.safeCast
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A marker utility interface for providers.
|
* A marker utility interface for providers.
|
||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
interface Provider {
|
public interface Provider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default target for this provider
|
* Default target for this provider
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
val defaultTarget: String get() = ""
|
public val defaultTarget: String get() = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default target for next chain segment
|
* Default target for next chain segment
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
val defaultChainTarget: String get() = ""
|
public val defaultChainTarget: String get() = ""
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of direct children for specific target
|
* A map of direct children for specific target
|
||||||
*/
|
*/
|
||||||
fun provideTop(target: String): Map<Name, Any>
|
public fun content(target: String): Map<Name, Any> = emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
|
public fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
|
||||||
if (path.length == 0) throw IllegalArgumentException("Can't provide by empty path")
|
if (path.length == 0) throw IllegalArgumentException("Can't provide by empty path")
|
||||||
val first = path.first()
|
val first = path.first()
|
||||||
val target = targetOverride ?: first.target ?: defaultTarget
|
val target = targetOverride ?: first.target ?: defaultTarget
|
||||||
val res = provideTop(target)[first.name] ?: return null
|
val res = content(target)[first.name] ?: return null
|
||||||
return when (path.length) {
|
return when (path.length) {
|
||||||
1 -> res
|
1 -> res
|
||||||
else -> {
|
else -> {
|
||||||
@ -65,24 +61,29 @@ fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
|
|||||||
/**
|
/**
|
||||||
* Type checked provide
|
* Type checked provide
|
||||||
*/
|
*/
|
||||||
inline fun <reified T : Any> Provider.provide(path: String): T? {
|
public inline fun <reified T : Any> Provider.provide(path: String, targetOverride: String? = null): T? {
|
||||||
return provide(Path.parse(path)) as? T
|
return provide(Path.parse(path), targetOverride) as? T
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
//inline fun <reified T : Any> Provider.provide(target: String, name: Name): T? {
|
||||||
|
// return provide(PathToken(name, target).toPath()) as? T
|
||||||
|
//}
|
||||||
|
|
||||||
inline fun <reified T : Any> Provider.provide(target: String, name: Name): T? {
|
//inline fun <reified T : Any> Provider.provide(target: String, name: String): T? =
|
||||||
return provide(PathToken(name, target).toPath()) as? T
|
// provide(target, name.toName())
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> Provider.provide(target: String, name: String): T? =
|
|
||||||
provide(target, name.toName())
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typed top level content
|
* Typed top level content
|
||||||
*/
|
*/
|
||||||
inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> {
|
public fun <T : Any> Provider.top(target: String, type: KClass<out T>): Map<Name, T> {
|
||||||
return provideTop(target).mapValues {
|
return content(target).mapValues {
|
||||||
it.value as? T ?: error("The type of element $it is ${it::class} but ${T::class} is expected")
|
type.safeCast(it.value) ?: error("The type of element $it is ${it::class} but $type is expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typed top level content
|
||||||
|
*/
|
||||||
|
public inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> = top(target, T::class)
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,4 +7,4 @@ package hep.dataforge.provider
|
|||||||
*/
|
*/
|
||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
annotation class Type(val id: String)
|
public annotation class Type(val id: String)
|
||||||
|
@ -11,7 +11,7 @@ class ContextTest {
|
|||||||
class DummyPlugin : AbstractPlugin() {
|
class DummyPlugin : AbstractPlugin() {
|
||||||
override val tag get() = PluginTag("test")
|
override val tag get() = PluginTag("test")
|
||||||
|
|
||||||
override fun provideTop(target: String): Map<Name, Any> {
|
override fun content(target: String): Map<Name, Any> {
|
||||||
return when(target){
|
return when(target){
|
||||||
"test" -> listOf("a", "b", "c.d").associate { it.toName() to it.toName() }
|
"test" -> listOf("a", "b", "c.d").associate { it.toName() to it.toName() }
|
||||||
else -> emptyMap()
|
else -> emptyMap()
|
||||||
@ -21,8 +21,11 @@ class ContextTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPluginManager() {
|
fun testPluginManager() {
|
||||||
Global.plugins.load(DummyPlugin())
|
val context = Global.context("test"){
|
||||||
val members = Global.content<Name>("test")
|
plugin(DummyPlugin())
|
||||||
|
}
|
||||||
|
//Global.plugins.load(DummyPlugin())
|
||||||
|
val members = context.gather<Name>("test")
|
||||||
assertEquals(3, members.count())
|
assertEquals(3, members.count())
|
||||||
members.forEach {
|
members.forEach {
|
||||||
assertEquals(it.key, it.value.appendLeft("test"))
|
assertEquals(it.key, it.value.appendLeft("test"))
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package hep.dataforge.context
|
|
||||||
|
|
||||||
|
|
||||||
actual object PluginRepository {
|
|
||||||
|
|
||||||
private val factories: MutableSet<PluginFactory<*>> = HashSet()
|
|
||||||
|
|
||||||
actual fun register(factory: PluginFactory<*>) {
|
|
||||||
factories.add(factory)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List plugins available in the repository
|
|
||||||
*/
|
|
||||||
actual fun list(): Sequence<PluginFactory<*>> = factories.asSequence()
|
|
||||||
}
|
|
@ -0,0 +1,32 @@
|
|||||||
|
package hep.dataforge.properties
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
fun HTMLInputElement.bindValue(property: Property<String>) {
|
||||||
|
if (this.onchange != null) error("Input element already bound")
|
||||||
|
this.onchange = {
|
||||||
|
property.value = this.value
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
property.onChange(this) {
|
||||||
|
if (value != it) {
|
||||||
|
value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
fun HTMLInputElement.bindChecked(property: Property<Boolean>) {
|
||||||
|
if (this.onchange != null) error("Input element already bound")
|
||||||
|
this.onchange = {
|
||||||
|
property.value = this.checked
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
property.onChange(this) {
|
||||||
|
if (checked != it) {
|
||||||
|
checked = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,24 +19,24 @@ import java.util.*
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.full.cast
|
import kotlin.reflect.full.cast
|
||||||
|
|
||||||
class ClassLoaderPlugin(val classLoader: ClassLoader) : AbstractPlugin() {
|
public class ClassLoaderPlugin(private val classLoader: ClassLoader) : AbstractPlugin() {
|
||||||
override val tag: PluginTag = PluginTag("classLoader", PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag("classLoader", PluginTag.DATAFORGE_GROUP)
|
||||||
|
|
||||||
private val serviceCache: MutableMap<Class<*>, ServiceLoader<*>> = HashMap()
|
private val serviceCache: MutableMap<Class<*>, ServiceLoader<*>> = HashMap()
|
||||||
|
|
||||||
fun <T : Any> services(type: KClass<T>): Sequence<T> {
|
public fun <T : Any> services(type: KClass<T>): Sequence<T> {
|
||||||
return serviceCache.getOrPut(type.java) { ServiceLoader.load(type.java, classLoader) }.asSequence()
|
return serviceCache.getOrPut(type.java) { ServiceLoader.load(type.java, classLoader) }.asSequence()
|
||||||
.map { type.cast(it) }
|
.map { type.cast(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
val DEFAULT = ClassLoaderPlugin(Global::class.java.classLoader)
|
public val DEFAULT: ClassLoaderPlugin = ClassLoaderPlugin(Global::class.java.classLoader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val Context.classLoaderPlugin get() = this.plugins.get() ?: ClassLoaderPlugin.DEFAULT
|
public val Context.classLoaderPlugin: ClassLoaderPlugin get() = this.plugins.get() ?: ClassLoaderPlugin.DEFAULT
|
||||||
|
|
||||||
inline fun <reified T : Any> Context.services() = classLoaderPlugin.services(T::class)
|
public inline fun <reified T : Any> Context.services(): Sequence<T> = classLoaderPlugin.services(T::class)
|
||||||
|
|
||||||
|
|
||||||
//open class JVMContext(
|
//open class JVMContext(
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package hep.dataforge.context
|
|
||||||
|
|
||||||
actual object PluginRepository {
|
|
||||||
|
|
||||||
private val factories: MutableSet<PluginFactory<*>> = HashSet()
|
|
||||||
|
|
||||||
actual fun register(factory: PluginFactory<*>) {
|
|
||||||
factories.add(factory)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List plugins available in the repository
|
|
||||||
*/
|
|
||||||
actual fun list(): Sequence<PluginFactory<*>> =
|
|
||||||
factories.asSequence() + Global.services()
|
|
||||||
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package hep.dataforge.provider
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.context.content
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.full.findAnnotation
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
object Types {
|
|
||||||
operator fun get(cl: KClass<*>): String {
|
|
||||||
return cl.findAnnotation<Type>()?.id ?: cl.simpleName ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun get(obj: Any): String {
|
|
||||||
return get(obj::class)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide an object with given name inferring target from its type using [Type] annotation
|
|
||||||
*/
|
|
||||||
inline fun <reified T : Any> Provider.provideByType(name: String): T? {
|
|
||||||
val target = Types[T::class]
|
|
||||||
return provide(target, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> Provider.provideByType(name: Name): T? {
|
|
||||||
val target = Types[T::class]
|
|
||||||
return provide(target, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> Provider.top(): Map<Name, T> {
|
|
||||||
val target = Types[T::class]
|
|
||||||
return top(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sequences of all objects provided by plugins with given target and type
|
|
||||||
*/
|
|
||||||
inline fun <reified T : Any> Context.content(): Map<Name, T> = content<T>(Types[T::class])
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
|||||||
|
package hep.dataforge.provider
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.context.gather
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
public val KClass<*>.dfType: String
|
||||||
|
get() = findAnnotation<Type>()?.id ?: simpleName ?: ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide an object with given name inferring target from its type using [Type] annotation
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public inline fun <reified T : Any> Provider.provideByType(name: String): T? {
|
||||||
|
val target = T::class.dfType
|
||||||
|
return provide(target, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
public inline fun <reified T : Any> Provider.top(): Map<Name, T> {
|
||||||
|
val target = T::class.dfType
|
||||||
|
return top(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All objects provided by plugins with given target and type
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public inline fun <reified T : Any> Context.gather(inherit: Boolean = true): Map<Name, T> =
|
||||||
|
gather<T>(T::class.dfType, inherit)
|
||||||
|
|
400
dataforge-data/api/dataforge-data.api
Normal file
400
dataforge-data/api/dataforge-data.api
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
public abstract interface class hep/dataforge/data/Action {
|
||||||
|
public abstract fun invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
|
||||||
|
public abstract fun isTerminal ()Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/Action$DefaultImpls {
|
||||||
|
public static fun isTerminal (Lhep/dataforge/data/Action;)Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/ActionEnv {
|
||||||
|
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun component1 ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun component2 ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun component3 ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun copy (Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/ActionEnv;
|
||||||
|
public static synthetic fun copy$default (Lhep/dataforge/data/ActionEnv;Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/data/ActionEnv;
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getActionMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
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/CoroutineMonitor : kotlin/coroutines/CoroutineContext$Element {
|
||||||
|
public static final field Companion Lhep/dataforge/data/CoroutineMonitor$Companion;
|
||||||
|
public fun <init> ()V
|
||||||
|
public final fun finish ()V
|
||||||
|
public fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
|
||||||
|
public fun get (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
|
||||||
|
public fun getKey ()Lkotlin/coroutines/CoroutineContext$Key;
|
||||||
|
public final fun getStatus ()Ljava/lang/String;
|
||||||
|
public final fun getTotalWork ()D
|
||||||
|
public final fun getWorkDone ()D
|
||||||
|
public fun minusKey (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
|
||||||
|
public fun plus (Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
|
||||||
|
public final fun setStatus (Ljava/lang/String;)V
|
||||||
|
public final fun setTotalWork (D)V
|
||||||
|
public final fun setWorkDone (D)V
|
||||||
|
public final fun start ()V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/CoroutineMonitor$Companion : kotlin/coroutines/CoroutineContext$Key {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/CoroutineMonitorKt {
|
||||||
|
public static final fun getDependencies (Lkotlinx/coroutines/Job;)Ljava/util/Collection;
|
||||||
|
public static final fun getMonitor (Lkotlin/coroutines/CoroutineContext;)Lhep/dataforge/data/CoroutineMonitor;
|
||||||
|
public static final fun getMonitor (Lkotlinx/coroutines/CoroutineScope;)Lhep/dataforge/data/CoroutineMonitor;
|
||||||
|
public static final fun getProgress (Lkotlinx/coroutines/Job;)D
|
||||||
|
public static final fun getStatus (Lkotlinx/coroutines/Job;)Ljava/lang/String;
|
||||||
|
public static final fun getTotalWork (Lkotlinx/coroutines/Job;)D
|
||||||
|
public static final fun getWorkDone (Lkotlinx/coroutines/Job;)D
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/data/Data : hep/dataforge/data/Goal, hep/dataforge/meta/MetaRepr {
|
||||||
|
public static final field Companion Lhep/dataforge/data/Data$Companion;
|
||||||
|
public static final field TYPE Ljava/lang/String;
|
||||||
|
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public abstract fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/Data$Companion {
|
||||||
|
public static final field TYPE Ljava/lang/String;
|
||||||
|
public final fun invoke (Ljava/lang/String;Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)Lhep/dataforge/data/Data;
|
||||||
|
public final fun invoke (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)Lhep/dataforge/data/Data;
|
||||||
|
public static synthetic fun invoke$default (Lhep/dataforge/data/Data$Companion;Ljava/lang/String;Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lhep/dataforge/data/Data;
|
||||||
|
public static synthetic fun invoke$default (Lhep/dataforge/data/Data$Companion;Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lhep/dataforge/data/Data;
|
||||||
|
public final fun static (Ljava/lang/Object;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/Data;
|
||||||
|
public static synthetic fun static$default (Lhep/dataforge/data/Data$Companion;Ljava/lang/Object;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/data/Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
public final fun getFrom ()Ljava/lang/String;
|
||||||
|
public final fun getPattern ()Ljava/lang/String;
|
||||||
|
public final fun getTo ()Ljava/lang/String;
|
||||||
|
public final fun setFrom (Ljava/lang/String;)V
|
||||||
|
public final fun setPattern (Ljava/lang/String;)V
|
||||||
|
public final fun setTo (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataFilter$Companion : hep/dataforge/meta/SchemeSpec {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataFilterKt {
|
||||||
|
public static final fun filter (Lhep/dataforge/data/DataNode;Lhep/dataforge/data/DataFilter;)Lhep/dataforge/data/DataNode;
|
||||||
|
public static final fun filter (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
|
||||||
|
public static final fun filter (Lhep/dataforge/data/DataNode;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/data/DataNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class hep/dataforge/data/DataItem : hep/dataforge/meta/MetaRepr {
|
||||||
|
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataItem$Leaf : hep/dataforge/data/DataItem {
|
||||||
|
public fun <init> (Lhep/dataforge/data/Data;)V
|
||||||
|
public final fun getData ()Lhep/dataforge/data/Data;
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataItem$Node : hep/dataforge/data/DataItem {
|
||||||
|
public fun <init> (Lhep/dataforge/data/DataNode;)V
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getNode ()Lhep/dataforge/data/DataNode;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataJVMKt {
|
||||||
|
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 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 abstract interface class hep/dataforge/data/DataNode : hep/dataforge/meta/MetaRepr {
|
||||||
|
public static final field Companion Lhep/dataforge/data/DataNode$Companion;
|
||||||
|
public static final field TYPE Ljava/lang/String;
|
||||||
|
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 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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/DataTreeBuilder {
|
||||||
|
public fun <init> (Lkotlin/reflect/KClass;)V
|
||||||
|
public final fun build ()Lhep/dataforge/data/DataTree;
|
||||||
|
public final fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public final fun meta (Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun meta (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MetaBuilder;
|
||||||
|
public final fun put (Ljava/lang/String;Lhep/dataforge/data/Data;)V
|
||||||
|
public final fun put (Ljava/lang/String;Lhep/dataforge/data/DataItem;)V
|
||||||
|
public final fun put (Ljava/lang/String;Lhep/dataforge/data/DataNode;)V
|
||||||
|
public final fun put (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/Name;Lhep/dataforge/data/Data;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/Name;Lhep/dataforge/data/DataItem;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/Name;Lhep/dataforge/data/DataNode;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/Name;Lhep/dataforge/data/DataTreeBuilder;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/NameToken;Lhep/dataforge/data/Data;)V
|
||||||
|
public final fun set (Lhep/dataforge/names/NameToken;Lhep/dataforge/data/DataTreeBuilder;)V
|
||||||
|
public final fun update (Lhep/dataforge/data/DataNode;)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
|
||||||
|
public fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
|
||||||
|
public fun get (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
|
||||||
|
public fun getKey ()Lkotlin/coroutines/CoroutineContext$Key;
|
||||||
|
public final fun getValues ()Ljava/util/Collection;
|
||||||
|
public fun minusKey (Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
|
||||||
|
public fun plus (Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/MetaBuilder;
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getResult ()Lkotlin/jvm/functions/Function2;
|
||||||
|
public final fun result (Lkotlin/jvm/functions/Function2;)V
|
||||||
|
public final fun setMeta (Lhep/dataforge/meta/MetaBuilder;)V
|
||||||
|
public final fun setResult (Lkotlin/jvm/functions/Function2;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/data/Goal {
|
||||||
|
public static final field Companion Lhep/dataforge/data/Goal$Companion;
|
||||||
|
public abstract fun getDependencies ()Ljava/util/Collection;
|
||||||
|
public abstract fun getResult ()Lkotlinx/coroutines/Deferred;
|
||||||
|
public abstract fun reset ()V
|
||||||
|
public abstract fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/Goal$Companion {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/GoalKt {
|
||||||
|
public static final fun await (Lhep/dataforge/data/Goal;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public static final fun isComplete (Lhep/dataforge/data/Goal;)Z
|
||||||
|
public static final fun map (Lhep/dataforge/data/Goal;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/Goal;
|
||||||
|
public static synthetic fun map$default (Lhep/dataforge/data/Goal;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/Goal;
|
||||||
|
public static final fun reduce (Ljava/util/Collection;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/Goal;
|
||||||
|
public static final fun reduce (Ljava/util/Map;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/Goal;
|
||||||
|
public static synthetic fun reduce$default (Ljava/util/Collection;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/Goal;
|
||||||
|
public static synthetic fun reduce$default (Ljava/util/Map;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/Goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/data/GroupRule {
|
||||||
|
public static final field Companion Lhep/dataforge/data/GroupRule$Companion;
|
||||||
|
public abstract fun invoke (Lhep/dataforge/data/DataNode;)Ljava/util/Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/GroupRule$Companion {
|
||||||
|
public final fun byMeta (Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/GroupRule;
|
||||||
|
public final fun byValue (Ljava/lang/String;Ljava/lang/String;)Lhep/dataforge/data/GroupRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/JoinGroup {
|
||||||
|
public field result Lkotlin/jvm/functions/Function3;
|
||||||
|
public fun <init> (Ljava/lang/String;Lhep/dataforge/data/DataNode;)V
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/MetaBuilder;
|
||||||
|
public final fun getName ()Ljava/lang/String;
|
||||||
|
public final fun getResult ()Lkotlin/jvm/functions/Function3;
|
||||||
|
public final fun result (Lkotlin/jvm/functions/Function3;)V
|
||||||
|
public final fun setMeta (Lhep/dataforge/meta/MetaBuilder;)V
|
||||||
|
public final fun setName (Ljava/lang/String;)V
|
||||||
|
public final fun setResult (Lkotlin/jvm/functions/Function3;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
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 invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
|
||||||
|
public fun isTerminal ()Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/MapActionBuilder {
|
||||||
|
public field result Lkotlin/jvm/functions/Function3;
|
||||||
|
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaBuilder;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun getActionMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/MetaBuilder;
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getResult ()Lkotlin/jvm/functions/Function3;
|
||||||
|
public final fun result (Lkotlin/jvm/functions/Function3;)V
|
||||||
|
public final fun setMeta (Lhep/dataforge/meta/MetaBuilder;)V
|
||||||
|
public final fun setName (Lhep/dataforge/names/Name;)V
|
||||||
|
public final fun setResult (Lkotlin/jvm/functions/Function3;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/NamedData : hep/dataforge/data/Data {
|
||||||
|
public fun <init> (Ljava/lang/String;Lhep/dataforge/data/Data;)V
|
||||||
|
public fun getDependencies ()Ljava/util/Collection;
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getName ()Ljava/lang/String;
|
||||||
|
public fun getResult ()Lkotlinx/coroutines/Deferred;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun reset ()V
|
||||||
|
public fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
|
||||||
|
public fun isTerminal ()Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/ReduceActionKt {
|
||||||
|
public static final fun get (Ljava/util/Map;Ljava/lang/String;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/ReduceGroupBuilder {
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun byValue (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public static synthetic fun byValue$default (Lhep/dataforge/data/ReduceGroupBuilder;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
|
||||||
|
public final fun getActionMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun group (Ljava/lang/String;Lhep/dataforge/data/DataFilter;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun group (Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun result (Ljava/lang/String;Lkotlin/jvm/functions/Function3;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
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 invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
|
||||||
|
public fun isTerminal ()Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/SplitBuilder {
|
||||||
|
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun fragment (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/StaticData : hep/dataforge/data/StaticGoal, hep/dataforge/data/Data {
|
||||||
|
public fun <init> (Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/Object;Lhep/dataforge/meta/Meta;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/StaticGoal : hep/dataforge/data/Goal {
|
||||||
|
public fun <init> (Ljava/lang/Object;)V
|
||||||
|
public fun getDependencies ()Ljava/util/Collection;
|
||||||
|
public fun getResult ()Lkotlinx/coroutines/Deferred;
|
||||||
|
public final fun getValue ()Ljava/lang/Object;
|
||||||
|
public fun reset ()V
|
||||||
|
public fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/data/TypeFilteredDataNode : hep/dataforge/data/DataNode {
|
||||||
|
public fun <init> (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)V
|
||||||
|
public fun getItems ()Ljava/util/Map;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -1,29 +1,23 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("ru.mipt.npm.mpp")
|
||||||
|
id("ru.mipt.npm.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
val coroutinesVersion: String = Scientifik.coroutinesVersion
|
kscience{
|
||||||
|
useCoroutines()
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting{
|
commonMain{
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-meta"))
|
api(project(":dataforge-meta"))
|
||||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvmMain{
|
||||||
val jvmMain by getting{
|
dependencies{
|
||||||
dependencies {
|
|
||||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
|
||||||
api(kotlin("reflect"))
|
api(kotlin("reflect"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val jsMain by getting{
|
|
||||||
dependencies {
|
|
||||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$coroutinesVersion")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,23 +5,23 @@ import hep.dataforge.meta.Meta
|
|||||||
/**
|
/**
|
||||||
* A simple data transformation on a data node
|
* A simple data transformation on a data node
|
||||||
*/
|
*/
|
||||||
interface Action<in T : Any, out R : Any> {
|
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
|
* Transform the data in the node, producing a new node. By default it is assumed that all calculations are lazy
|
||||||
* so not actual computation is started at this moment
|
* so not actual computation is started at this moment
|
||||||
*/
|
*/
|
||||||
operator fun invoke(node: DataNode<T>, meta: Meta): DataNode<R>
|
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
|
* Terminal action is the one that could not be invoked lazily and requires some kind of blocking computation to invoke
|
||||||
*/
|
*/
|
||||||
val isTerminal: Boolean get() = false
|
public val isTerminal: Boolean get() = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action composition. The result is terminal if one of its parts is terminal
|
* Action composition. The result is terminal if one of its parts is terminal
|
||||||
*/
|
*/
|
||||||
infix fun <T : Any, I : Any, R : Any> Action<T, I>.then(action: Action<I, R>): Action<T, R> {
|
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
|
// TODO introduce composite action and add optimize by adding action to the list
|
||||||
return object : Action<T, R> {
|
return object : Action<T, R> {
|
||||||
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
||||||
|
@ -1,48 +1,58 @@
|
|||||||
package hep.dataforge.data
|
package hep.dataforge.data
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A monitor of goal state that could be accessed only form inside the goal
|
* A monitor of goal state that could be accessed only form inside the goal
|
||||||
*/
|
*/
|
||||||
class CoroutineMonitor : CoroutineContext.Element {
|
@DFExperimental
|
||||||
|
public class CoroutineMonitor : CoroutineContext.Element {
|
||||||
override val key: CoroutineContext.Key<*> get() = CoroutineMonitor
|
override val key: CoroutineContext.Key<*> get() = CoroutineMonitor
|
||||||
|
|
||||||
var totalWork: Double = 1.0
|
public var totalWork: Double = 1.0
|
||||||
var workDone: Double = 0.0
|
public var workDone: Double = 0.0
|
||||||
var status: String = ""
|
public var status: String = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the goal as started
|
* Mark the goal as started
|
||||||
*/
|
*/
|
||||||
fun start() {
|
public fun start() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the goal as completed
|
* Mark the goal as completed
|
||||||
*/
|
*/
|
||||||
fun finish() {
|
public fun finish() {
|
||||||
workDone = totalWork
|
workDone = totalWork
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : CoroutineContext.Key<CoroutineMonitor>
|
public companion object : CoroutineContext.Key<CoroutineMonitor>
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dependencies(val values: Collection<Job>) : CoroutineContext.Element {
|
public class Dependencies(public val values: Collection<Job>) : CoroutineContext.Element {
|
||||||
override val key: CoroutineContext.Key<*> get() = Dependencies
|
override val key: CoroutineContext.Key<*> get() = Dependencies
|
||||||
|
|
||||||
companion object : CoroutineContext.Key<Dependencies>
|
public companion object : CoroutineContext.Key<Dependencies>
|
||||||
}
|
}
|
||||||
|
|
||||||
val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor]
|
@DFExperimental
|
||||||
val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor
|
public val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor]
|
||||||
|
@DFExperimental
|
||||||
|
public val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor
|
||||||
|
|
||||||
val Job.dependencies: Collection<Job> get() = this[Dependencies]?.values ?: emptyList()
|
public val Job.dependencies: Collection<Job> get() = this[Dependencies]?.values ?: emptyList()
|
||||||
|
|
||||||
val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0)
|
@DFExperimental
|
||||||
val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0)
|
public val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0)
|
||||||
val Job.status: String get() = monitor?.status ?: ""
|
@DFExperimental
|
||||||
val Job.progress: Double get() = workDone / totalWork
|
public val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0)
|
||||||
|
@DFExperimental
|
||||||
|
public val Job.status: String get() = monitor?.status ?: ""
|
||||||
|
@DFExperimental
|
||||||
|
public val Job.progress: Double get() = workDone / totalWork
|
@ -11,15 +11,16 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* A data element characterized by its meta
|
* A data element characterized by its meta
|
||||||
*/
|
*/
|
||||||
interface Data<out T : Any> : Goal<T>, MetaRepr{
|
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.
|
* Type marker for the data. The type is known before the calculation takes place so it could be checked.
|
||||||
*/
|
*/
|
||||||
val type: KClass<out T>
|
public val type: KClass<out T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta for the data
|
* Meta for the data
|
||||||
*/
|
*/
|
||||||
val meta: Meta
|
public val meta: Meta
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
"type" put (type.simpleName?:"undefined")
|
"type" put (type.simpleName?:"undefined")
|
||||||
@ -28,10 +29,10 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val TYPE = "data"
|
public const val TYPE: String = "data"
|
||||||
|
|
||||||
operator fun <T : Any> invoke(
|
public operator fun <T : Any> invoke(
|
||||||
type: KClass<out T>,
|
type: KClass<out T>,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
@ -39,14 +40,14 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
|||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Data<T> = DynamicData(type, meta, context, dependencies, block)
|
): Data<T> = DynamicData(type, meta, context, dependencies, block)
|
||||||
|
|
||||||
inline operator fun <reified T : Any> invoke(
|
public inline operator fun <reified T : Any> invoke(
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
dependencies: Collection<Data<*>> = emptyList(),
|
dependencies: Collection<Data<*>> = emptyList(),
|
||||||
noinline block: suspend CoroutineScope.() -> T
|
noinline block: suspend CoroutineScope.() -> T
|
||||||
): Data<T> = invoke(T::class, meta, context, dependencies, block)
|
): Data<T> = invoke(T::class, meta, context, dependencies, block)
|
||||||
|
|
||||||
operator fun <T : Any> invoke(
|
public operator fun <T : Any> invoke(
|
||||||
name: String,
|
name: String,
|
||||||
type: KClass<out T>,
|
type: KClass<out T>,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
@ -55,7 +56,7 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
|||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Data<T> = NamedData(name, invoke(type, meta, context, dependencies, block))
|
): Data<T> = NamedData(name, invoke(type, meta, context, dependencies, block))
|
||||||
|
|
||||||
inline operator fun <reified T : Any> invoke(
|
public inline operator fun <reified T : Any> invoke(
|
||||||
name: String,
|
name: String,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
@ -64,13 +65,13 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
|||||||
): Data<T> =
|
): Data<T> =
|
||||||
invoke(name, T::class, meta, context, dependencies, block)
|
invoke(name, T::class, meta, context, dependencies, block)
|
||||||
|
|
||||||
fun <T : Any> static(value: T, meta: Meta = Meta.EMPTY): Data<T> =
|
public fun <T : Any> static(value: T, meta: Meta = Meta.EMPTY): Data<T> =
|
||||||
StaticData(value, meta)
|
StaticData(value, meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DynamicData<T : Any>(
|
public class DynamicData<T : Any>(
|
||||||
override val type: KClass<out T>,
|
override val type: KClass<out T>,
|
||||||
override val meta: Meta = Meta.EMPTY,
|
override val meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
@ -78,16 +79,16 @@ class DynamicData<T : Any>(
|
|||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
) : Data<T>, DynamicGoal<T>(context, dependencies, block)
|
) : Data<T>, DynamicGoal<T>(context, dependencies, block)
|
||||||
|
|
||||||
class StaticData<T : Any>(
|
public class StaticData<T : Any>(
|
||||||
value: T,
|
value: T,
|
||||||
override val meta: Meta = Meta.EMPTY
|
override val meta: Meta = Meta.EMPTY
|
||||||
) : Data<T>, StaticGoal<T>(value) {
|
) : Data<T>, StaticGoal<T>(value) {
|
||||||
override val type: KClass<out T> get() = value::class
|
override val type: KClass<out T> get() = value::class
|
||||||
}
|
}
|
||||||
|
|
||||||
class NamedData<out T : Any>(val name: String, data: Data<T>) : Data<T> by data
|
public class NamedData<out T : Any>(public val name: String, data: Data<T>) : Data<T> by data
|
||||||
|
|
||||||
fun <T : Any, R : Any> Data<T>.map(
|
public fun <T : Any, R : Any> Data<T>.map(
|
||||||
outputType: KClass<out R>,
|
outputType: KClass<out R>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = this.meta,
|
meta: Meta = this.meta,
|
||||||
@ -100,7 +101,7 @@ fun <T : Any, R : Any> Data<T>.map(
|
|||||||
/**
|
/**
|
||||||
* Create a data pipe
|
* Create a data pipe
|
||||||
*/
|
*/
|
||||||
inline fun <T : Any, reified R : Any> Data<T>.map(
|
public inline fun <T : Any, reified R : Any> Data<T>.map(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = this.meta,
|
meta: Meta = this.meta,
|
||||||
noinline block: suspend CoroutineScope.(T) -> R
|
noinline block: suspend CoroutineScope.(T) -> R
|
||||||
@ -111,7 +112,7 @@ inline fun <T : Any, reified R : Any> Data<T>.map(
|
|||||||
/**
|
/**
|
||||||
* Create a joined data.
|
* Create a joined data.
|
||||||
*/
|
*/
|
||||||
inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduce(
|
public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduce(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
noinline block: suspend CoroutineScope.(Collection<T>) -> R
|
noinline block: suspend CoroutineScope.(Collection<T>) -> R
|
||||||
@ -124,7 +125,7 @@ inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduce(
|
|||||||
block(map { run { it.await() } })
|
block(map { run { it.await() } })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <K, T : Any, R : Any> Map<K, Data<T>>.reduce(
|
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduce(
|
||||||
outputType: KClass<out R>,
|
outputType: KClass<out R>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
@ -145,7 +146,7 @@ fun <K, T : Any, R : Any> Map<K, Data<T>>.reduce(
|
|||||||
* @param T type of the input goal
|
* @param T type of the input goal
|
||||||
* @param R type of the result goal
|
* @param R type of the result goal
|
||||||
*/
|
*/
|
||||||
inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduce(
|
public inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduce(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
noinline block: suspend CoroutineScope.(Map<K, T>) -> R
|
noinline block: suspend CoroutineScope.(Map<K, T>) -> R
|
||||||
|
@ -4,31 +4,29 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
|
|
||||||
|
|
||||||
class DataFilter : Scheme() {
|
public class DataFilter : Scheme() {
|
||||||
/**
|
/**
|
||||||
* A source node for the filter
|
* A source node for the filter
|
||||||
*/
|
*/
|
||||||
var from by string()
|
public var from: String? by string()
|
||||||
/**
|
/**
|
||||||
* A target placement for the filtered node
|
* A target placement for the filtered node
|
||||||
*/
|
*/
|
||||||
var to by string()
|
public var to: String? by string()
|
||||||
/**
|
/**
|
||||||
* A regular expression pattern for the filter
|
* A regular expression pattern for the filter
|
||||||
*/
|
*/
|
||||||
var pattern by string(".*")
|
public var pattern: String by string(".*")
|
||||||
// val prefix by string()
|
// val prefix by string()
|
||||||
// val suffix by string()
|
// val suffix by string()
|
||||||
|
|
||||||
fun isEmpty(): Boolean = config.isEmpty()
|
public companion object : SchemeSpec<DataFilter>(::DataFilter)
|
||||||
|
|
||||||
companion object : SchemeSpec<DataFilter>(::DataFilter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply meta-based filter to given data node
|
* Apply meta-based filter to given data node
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.filter(filter: DataFilter): DataNode<T> {
|
public fun <T : Any> DataNode<T>.filter(filter: DataFilter): DataNode<T> {
|
||||||
val sourceNode = filter.from?.let { get(it.toName()).node } ?: this@filter
|
val sourceNode = filter.from?.let { get(it.toName()).node } ?: this@filter
|
||||||
val regex = filter.pattern.toRegex()
|
val regex = filter.pattern.toRegex()
|
||||||
val targetNode = DataTreeBuilder(type).apply {
|
val targetNode = DataTreeBuilder(type).apply {
|
||||||
@ -46,10 +44,10 @@ fun <T : Any> DataNode<T>.filter(filter: DataFilter): DataNode<T> {
|
|||||||
/**
|
/**
|
||||||
* Filter data using [DataFilter] specification
|
* Filter data using [DataFilter] specification
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.filter(filter: Meta): DataNode<T> = filter(DataFilter.wrap(filter))
|
public fun <T : Any> DataNode<T>.filter(filter: Meta): DataNode<T> = filter(DataFilter.read(filter))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter data using [DataFilter] builder
|
* Filter data using [DataFilter] builder
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.filter(filterBuilder: DataFilter.() -> Unit): DataNode<T> =
|
public fun <T : Any> DataNode<T>.filter(filterBuilder: DataFilter.() -> Unit): DataNode<T> =
|
||||||
filter(DataFilter(filterBuilder))
|
filter(DataFilter(filterBuilder))
|
@ -11,12 +11,12 @@ import kotlin.collections.component2
|
|||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
sealed class DataItem<out T : Any> : MetaRepr {
|
public sealed class DataItem<out T : Any> : MetaRepr {
|
||||||
abstract val type: KClass<out T>
|
public abstract val type: KClass<out T>
|
||||||
|
|
||||||
abstract val meta: Meta
|
public abstract val meta: Meta
|
||||||
|
|
||||||
class Node<out T : Any>(val node: DataNode<T>) : DataItem<T>() {
|
public class Node<out T : Any>(public val node: DataNode<T>) : DataItem<T>() {
|
||||||
override val type: KClass<out T> get() = node.type
|
override val type: KClass<out T> get() = node.type
|
||||||
|
|
||||||
override fun toMeta(): Meta = node.toMeta()
|
override fun toMeta(): Meta = node.toMeta()
|
||||||
@ -24,7 +24,7 @@ sealed class DataItem<out T : Any> : MetaRepr {
|
|||||||
override val meta: Meta get() = node.meta
|
override val meta: Meta get() = node.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
class Leaf<out T : Any>(val data: Data<T>) : DataItem<T>() {
|
public class Leaf<out T : Any>(public val data: Data<T>) : DataItem<T>() {
|
||||||
override val type: KClass<out T> get() = data.type
|
override val type: KClass<out T> get() = data.type
|
||||||
|
|
||||||
override fun toMeta(): Meta = data.toMeta()
|
override fun toMeta(): Meta = data.toMeta()
|
||||||
@ -36,16 +36,16 @@ sealed class DataItem<out T : Any> : MetaRepr {
|
|||||||
/**
|
/**
|
||||||
* A tree-like data structure grouped into the node. All data inside the node must inherit its type
|
* A tree-like data structure grouped into the node. All data inside the node must inherit its type
|
||||||
*/
|
*/
|
||||||
interface DataNode<out T : Any> : MetaRepr {
|
public interface DataNode<out T : Any> : MetaRepr {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimal common ancestor to all data in the node
|
* The minimal common ancestor to all data in the node
|
||||||
*/
|
*/
|
||||||
val type: KClass<out T>
|
public val type: KClass<out T>
|
||||||
|
|
||||||
val items: Map<NameToken, DataItem<T>>
|
public val items: Map<NameToken, DataItem<T>>
|
||||||
|
|
||||||
val meta: Meta
|
public val meta: Meta
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
"type" put (type.simpleName ?: "undefined")
|
"type" put (type.simpleName ?: "undefined")
|
||||||
@ -60,7 +60,7 @@ interface DataNode<out T : Any> : MetaRepr {
|
|||||||
* Start computation for all goals in data node and return a job for the whole node
|
* Start computation for all goals in data node and return a job for the whole node
|
||||||
*/
|
*/
|
||||||
@Suppress("DeferredResultUnused")
|
@Suppress("DeferredResultUnused")
|
||||||
fun CoroutineScope.startAll(): Job = launch {
|
public fun CoroutineScope.startAll(): Job = launch {
|
||||||
items.values.forEach {
|
items.values.forEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
is DataItem.Node<*> -> it.node.run { startAll() }
|
is DataItem.Node<*> -> it.node.run { startAll() }
|
||||||
@ -69,36 +69,36 @@ interface DataNode<out T : Any> : MetaRepr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val TYPE = "dataNode"
|
public const val TYPE: String = "dataNode"
|
||||||
|
|
||||||
operator fun <T : Any> invoke(type: KClass<out T>, block: DataTreeBuilder<T>.() -> Unit) =
|
public operator fun <T : Any> invoke(type: KClass<out T>, block: DataTreeBuilder<T>.() -> Unit): DataTree<T> =
|
||||||
DataTreeBuilder(type).apply(block).build()
|
DataTreeBuilder(type).apply(block).build()
|
||||||
|
|
||||||
inline operator fun <reified T : Any> invoke(noinline block: DataTreeBuilder<T>.() -> Unit) =
|
public inline operator fun <reified T : Any> invoke(noinline block: DataTreeBuilder<T>.() -> Unit): DataTree<T> =
|
||||||
DataTreeBuilder(T::class).apply(block).build()
|
DataTreeBuilder(T::class).apply(block).build()
|
||||||
|
|
||||||
fun <T : Any> builder(type: KClass<out T>) = DataTreeBuilder(type)
|
public fun <T : Any> builder(type: KClass<out T>): DataTreeBuilder<T> = DataTreeBuilder(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T: Any> DataNode<T>.join(): Unit = coroutineScope { startAll().join() }
|
public suspend fun <T: Any> DataNode<T>.join(): Unit = coroutineScope { startAll().join() }
|
||||||
|
|
||||||
val <T : Any> DataItem<T>?.node: DataNode<T>? get() = (this as? DataItem.Node<T>)?.node
|
public val <T : Any> DataItem<T>?.node: DataNode<T>? get() = (this as? DataItem.Node<T>)?.node
|
||||||
val <T : Any> DataItem<T>?.data: Data<T>? get() = (this as? DataItem.Leaf<T>)?.data
|
public val <T : Any> DataItem<T>?.data: Data<T>? get() = (this as? DataItem.Leaf<T>)?.data
|
||||||
|
|
||||||
operator fun <T : Any> DataNode<T>.get(name: Name): DataItem<T>? = when (name.length) {
|
public operator fun <T : Any> DataNode<T>.get(name: Name): DataItem<T>? = when (name.length) {
|
||||||
0 -> error("Empty name")
|
0 -> error("Empty name")
|
||||||
1 -> items[name.first()]
|
1 -> items[name.firstOrNull()]
|
||||||
else -> get(name.first()!!.asName()).node?.get(name.cutFirst())
|
else -> get(name.firstOrNull()!!.asName()).node?.get(name.cutFirst())
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <T : Any> DataNode<T>.get(name: String): DataItem<T>? = get(name.toName())
|
public operator fun <T : Any> DataNode<T>.get(name: String): DataItem<T>? = get(name.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sequence of all children including nodes
|
* Sequence of all children including nodes
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.asSequence(): Sequence<Pair<Name, DataItem<T>>> = sequence {
|
public fun <T : Any> DataNode<T>.asSequence(): Sequence<Pair<Name, DataItem<T>>> = sequence {
|
||||||
items.forEach { (head, item) ->
|
items.forEach { (head, item) ->
|
||||||
yield(head.asName() to item)
|
yield(head.asName() to item)
|
||||||
if (item is DataItem.Node) {
|
if (item is DataItem.Node) {
|
||||||
@ -112,7 +112,7 @@ fun <T : Any> DataNode<T>.asSequence(): Sequence<Pair<Name, DataItem<T>>> = sequ
|
|||||||
/**
|
/**
|
||||||
* Sequence of data entries
|
* Sequence of data entries
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.dataSequence(): Sequence<Pair<Name, Data<T>>> = sequence {
|
public fun <T : Any> DataNode<T>.dataSequence(): Sequence<Pair<Name, Data<T>>> = sequence {
|
||||||
items.forEach { (head, item) ->
|
items.forEach { (head, item) ->
|
||||||
when (item) {
|
when (item) {
|
||||||
is DataItem.Leaf -> yield(head.asName() to item.data)
|
is DataItem.Leaf -> yield(head.asName() to item.data)
|
||||||
@ -125,9 +125,9 @@ fun <T : Any> DataNode<T>.dataSequence(): Sequence<Pair<Name, Data<T>>> = sequen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <T : Any> DataNode<T>.iterator(): Iterator<Pair<Name, DataItem<T>>> = asSequence().iterator()
|
public operator fun <T : Any> DataNode<T>.iterator(): Iterator<Pair<Name, DataItem<T>>> = asSequence().iterator()
|
||||||
|
|
||||||
class DataTree<out T : Any> internal constructor(
|
public class DataTree<out T : Any> internal constructor(
|
||||||
override val type: KClass<out T>,
|
override val type: KClass<out T>,
|
||||||
override val items: Map<NameToken, DataItem<T>>,
|
override val items: Map<NameToken, DataItem<T>>,
|
||||||
override val meta: Meta
|
override val meta: Meta
|
||||||
@ -142,17 +142,17 @@ private sealed class DataTreeBuilderItem<out T : Any> {
|
|||||||
* A builder for a DataTree.
|
* A builder for a DataTree.
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
public class DataTreeBuilder<T : Any>(public val type: KClass<out T>) {
|
||||||
private val map = HashMap<NameToken, DataTreeBuilderItem<T>>()
|
private val map = HashMap<NameToken, DataTreeBuilderItem<T>>()
|
||||||
|
|
||||||
private var meta = MetaBuilder()
|
private var meta = MetaBuilder()
|
||||||
|
|
||||||
operator fun set(token: NameToken, node: DataTreeBuilder<out T>) {
|
public operator fun set(token: NameToken, node: DataTreeBuilder<out T>) {
|
||||||
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
|
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
|
||||||
map[token] = DataTreeBuilderItem.Node(node)
|
map[token] = DataTreeBuilderItem.Node(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(token: NameToken, data: Data<T>) {
|
public operator fun set(token: NameToken, data: Data<T>) {
|
||||||
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
|
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
|
||||||
map[token] = DataTreeBuilderItem.Leaf(data)
|
map[token] = DataTreeBuilderItem.Leaf(data)
|
||||||
}
|
}
|
||||||
@ -168,30 +168,30 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
|||||||
private fun buildNode(name: Name): DataTreeBuilder<T> {
|
private fun buildNode(name: Name): DataTreeBuilder<T> {
|
||||||
return when (name.length) {
|
return when (name.length) {
|
||||||
0 -> this
|
0 -> this
|
||||||
1 -> buildNode(name.first()!!)
|
1 -> buildNode(name.firstOrNull()!!)
|
||||||
else -> buildNode(name.first()!!).buildNode(name.cutFirst())
|
else -> buildNode(name.firstOrNull()!!).buildNode(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(name: Name, data: Data<T>) {
|
public operator fun set(name: Name, data: Data<T>) {
|
||||||
when (name.length) {
|
when (name.length) {
|
||||||
0 -> error("Can't add data with empty name")
|
0 -> error("Can't add data with empty name")
|
||||||
1 -> set(name.first()!!, data)
|
1 -> set(name.firstOrNull()!!, data)
|
||||||
2 -> buildNode(name.cutLast())[name.last()!!] = data
|
2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(name: Name, node: DataTreeBuilder<out T>) {
|
public operator fun set(name: Name, node: DataTreeBuilder<out T>) {
|
||||||
when (name.length) {
|
when (name.length) {
|
||||||
0 -> error("Can't add data with empty name")
|
0 -> error("Can't add data with empty name")
|
||||||
1 -> set(name.first()!!, node)
|
1 -> set(name.firstOrNull()!!, node)
|
||||||
2 -> buildNode(name.cutLast())[name.last()!!] = node
|
2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(name: Name, node: DataNode<T>) = set(name, node.builder())
|
public operator fun set(name: Name, node: DataNode<T>): Unit = set(name, node.builder())
|
||||||
|
|
||||||
operator fun set(name: Name, item: DataItem<T>) = when (item) {
|
public operator fun set(name: Name, item: DataItem<T>): Unit = when (item) {
|
||||||
is DataItem.Node<T> -> set(name, item.node.builder())
|
is DataItem.Node<T> -> set(name, item.node.builder())
|
||||||
is DataItem.Leaf<T> -> set(name, item.data)
|
is DataItem.Leaf<T> -> set(name, item.data)
|
||||||
}
|
}
|
||||||
@ -199,25 +199,25 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
|||||||
/**
|
/**
|
||||||
* Append data to node
|
* Append data to node
|
||||||
*/
|
*/
|
||||||
infix fun String.put(data: Data<T>) = set(toName(), data)
|
public infix fun String.put(data: Data<T>): Unit = set(toName(), data)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append node
|
* Append node
|
||||||
*/
|
*/
|
||||||
infix fun String.put(node: DataNode<T>) = set(toName(), node)
|
public infix fun String.put(node: DataNode<T>): Unit = set(toName(), node)
|
||||||
|
|
||||||
infix fun String.put(item: DataItem<T>) = set(toName(), item)
|
public infix fun String.put(item: DataItem<T>): Unit = set(toName(), item)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and append node
|
* Build and append node
|
||||||
*/
|
*/
|
||||||
infix fun String.put(block: DataTreeBuilder<T>.() -> Unit) = set(toName(), DataTreeBuilder(type).apply(block))
|
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.
|
* Update data with given node data and meta with node meta.
|
||||||
*/
|
*/
|
||||||
fun update(node: DataNode<T>) {
|
public fun update(node: DataNode<T>) {
|
||||||
node.dataSequence().forEach {
|
node.dataSequence().forEach {
|
||||||
//TODO check if the place is occupied
|
//TODO check if the place is occupied
|
||||||
this[it.first] = it.second
|
this[it.first] = it.second
|
||||||
@ -225,13 +225,13 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
|||||||
meta.update(node.meta)
|
meta.update(node.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun meta(block: MetaBuilder.() -> Unit) = meta.apply(block)
|
public fun meta(block: MetaBuilder.() -> Unit): MetaBuilder = meta.apply(block)
|
||||||
|
|
||||||
fun meta(meta: Meta) {
|
public fun meta(meta: Meta) {
|
||||||
this.meta = meta.builder()
|
this.meta = meta.builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): DataTree<T> {
|
public fun build(): DataTree<T> {
|
||||||
val resMap = map.mapValues { (_, value) ->
|
val resMap = map.mapValues { (_, value) ->
|
||||||
when (value) {
|
when (value) {
|
||||||
is DataTreeBuilderItem.Leaf -> DataItem.Leaf(value.value)
|
is DataTreeBuilderItem.Leaf -> DataItem.Leaf(value.value)
|
||||||
@ -242,50 +242,50 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.datum(name: Name, data: Data<T>) {
|
public fun <T : Any> DataTreeBuilder<T>.datum(name: Name, data: Data<T>) {
|
||||||
this[name] = data
|
this[name] = data
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.datum(name: String, data: Data<T>) {
|
public fun <T : Any> DataTreeBuilder<T>.datum(name: String, data: Data<T>) {
|
||||||
this[name.toName()] = data
|
this[name.toName()] = data
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, meta: Meta = Meta.EMPTY) {
|
public fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, meta: Meta = Meta.EMPTY) {
|
||||||
this[name] = Data.static(data, meta)
|
this[name] = Data.static(data, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, block: MetaBuilder.() -> Unit = {}) {
|
public fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, block: MetaBuilder.() -> Unit = {}) {
|
||||||
this[name] = Data.static(data, Meta(block))
|
this[name] = Data.static(data, Meta(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.static(name: String, data: T, block: MetaBuilder.() -> Unit = {}) {
|
public fun <T : Any> DataTreeBuilder<T>.static(name: String, data: T, block: MetaBuilder.() -> Unit = {}) {
|
||||||
this[name.toName()] = Data.static(data, Meta(block))
|
this[name.toName()] = Data.static(data, Meta(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.node(name: Name, node: DataNode<T>) {
|
public fun <T : Any> DataTreeBuilder<T>.node(name: Name, node: DataNode<T>) {
|
||||||
this[name] = node
|
this[name] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataTreeBuilder<T>.node(name: String, node: DataNode<T>) {
|
public fun <T : Any> DataTreeBuilder<T>.node(name: String, node: DataNode<T>) {
|
||||||
this[name.toName()] = node
|
this[name.toName()] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any> DataTreeBuilder<T>.node(name: Name, noinline block: DataTreeBuilder<T>.() -> Unit) {
|
public inline fun <reified T : Any> DataTreeBuilder<T>.node(name: Name, noinline block: DataTreeBuilder<T>.() -> Unit) {
|
||||||
this[name] = DataNode(T::class, block)
|
this[name] = DataNode(T::class, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any> DataTreeBuilder<T>.node(name: String, noinline block: DataTreeBuilder<T>.() -> Unit) {
|
public inline fun <reified T : Any> DataTreeBuilder<T>.node(name: String, noinline block: DataTreeBuilder<T>.() -> Unit) {
|
||||||
this[name.toName()] = DataNode(T::class, block)
|
this[name.toName()] = DataNode(T::class, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a mutable builder from this node. Node content is not changed
|
* Generate a mutable builder from this node. Node content is not changed
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<T>.builder(): DataTreeBuilder<T> = DataTreeBuilder(type).apply {
|
public fun <T : Any> DataNode<T>.builder(): DataTreeBuilder<T> = DataTreeBuilder(type).apply {
|
||||||
dataSequence().forEach { (name, data) -> this[name] = data }
|
dataSequence().forEach { (name, data) -> this[name] = data }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataNode<T>.filter(predicate: (Name, Data<T>) -> Boolean): DataNode<T> = DataNode.invoke(type) {
|
public fun <T : Any> DataNode<T>.filter(predicate: (Name, Data<T>) -> Boolean): DataNode<T> = DataNode.invoke(type) {
|
||||||
dataSequence().forEach { (name, data) ->
|
dataSequence().forEach { (name, data) ->
|
||||||
if (predicate(name, data)) {
|
if (predicate(name, data)) {
|
||||||
this[name] = data
|
this[name] = data
|
||||||
@ -293,4 +293,4 @@ fun <T : Any> DataNode<T>.filter(predicate: (Name, Data<T>) -> Boolean): DataNod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataNode<T>.first(): Data<T>? = dataSequence().first().second
|
public fun <T : Any> DataNode<T>.first(): Data<T>? = dataSequence().first().second
|
@ -1,37 +1,36 @@
|
|||||||
package hep.dataforge.data
|
package hep.dataforge.data
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
interface Goal<out T> {
|
public interface Goal<out T> {
|
||||||
val dependencies: Collection<Goal<*>>
|
public val dependencies: Collection<Goal<*>>
|
||||||
/**
|
/**
|
||||||
* Returns current running coroutine if the goal is started
|
* Returns current running coroutine if the goal is started
|
||||||
*/
|
*/
|
||||||
val result: Deferred<T>?
|
public val result: Deferred<T>?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get ongoing computation or start a new one.
|
* Get ongoing computation or start a new one.
|
||||||
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
|
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
|
||||||
*/
|
*/
|
||||||
fun CoroutineScope.startAsync(): Deferred<T>
|
public fun CoroutineScope.startAsync(): Deferred<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the computation
|
* Reset the computation
|
||||||
*/
|
*/
|
||||||
fun reset()
|
public fun reset()
|
||||||
|
|
||||||
companion object {
|
public companion object
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> Goal<T>.await(): T = coroutineScope { startAsync().await() }
|
public suspend fun <T> Goal<T>.await(): T = coroutineScope { startAsync().await() }
|
||||||
|
|
||||||
val Goal<*>.isComplete get() = result?.isCompleted ?: false
|
public val Goal<*>.isComplete: Boolean get() = result?.isCompleted ?: false
|
||||||
|
|
||||||
open class StaticGoal<T>(val value: T) : Goal<T> {
|
public open class StaticGoal<T>(public val value: T) : Goal<T> {
|
||||||
override val dependencies: Collection<Goal<*>> get() = emptyList()
|
override val dependencies: Collection<Goal<*>> get() = emptyList()
|
||||||
override val result: Deferred<T> = CompletableDeferred(value)
|
override val result: Deferred<T> = CompletableDeferred(value)
|
||||||
|
|
||||||
@ -42,10 +41,10 @@ open class StaticGoal<T>(val value: T) : Goal<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class DynamicGoal<T>(
|
public open class DynamicGoal<T>(
|
||||||
val coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
private val coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
override val dependencies: Collection<Goal<*>> = emptyList(),
|
override val dependencies: Collection<Goal<*>> = emptyList(),
|
||||||
val block: suspend CoroutineScope.() -> T
|
public val block: suspend CoroutineScope.() -> T
|
||||||
) : Goal<T> {
|
) : Goal<T> {
|
||||||
|
|
||||||
final override var result: Deferred<T>? = null
|
final override var result: Deferred<T>? = null
|
||||||
@ -55,6 +54,7 @@ open class DynamicGoal<T>(
|
|||||||
* Get ongoing computation or start a new one.
|
* Get ongoing computation or start a new one.
|
||||||
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
|
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
|
||||||
*/
|
*/
|
||||||
|
@DFExperimental
|
||||||
override fun CoroutineScope.startAsync(): Deferred<T> {
|
override fun CoroutineScope.startAsync(): Deferred<T> {
|
||||||
val startedDependencies = this@DynamicGoal.dependencies.map { goal ->
|
val startedDependencies = this@DynamicGoal.dependencies.map { goal ->
|
||||||
goal.run { startAsync() }
|
goal.run { startAsync() }
|
||||||
@ -82,7 +82,7 @@ open class DynamicGoal<T>(
|
|||||||
/**
|
/**
|
||||||
* Create a one-to-one goal based on existing goal
|
* Create a one-to-one goal based on existing goal
|
||||||
*/
|
*/
|
||||||
fun <T, R> Goal<T>.map(
|
public fun <T, R> Goal<T>.map(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
block: suspend CoroutineScope.(T) -> R
|
block: suspend CoroutineScope.(T) -> R
|
||||||
): Goal<R> = DynamicGoal(coroutineContext, listOf(this)) {
|
): Goal<R> = DynamicGoal(coroutineContext, listOf(this)) {
|
||||||
@ -92,7 +92,7 @@ fun <T, R> Goal<T>.map(
|
|||||||
/**
|
/**
|
||||||
* Create a joining goal.
|
* Create a joining goal.
|
||||||
*/
|
*/
|
||||||
fun <T, R> Collection<Goal<T>>.reduce(
|
public fun <T, R> Collection<Goal<T>>.reduce(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
block: suspend CoroutineScope.(Collection<T>) -> R
|
block: suspend CoroutineScope.(Collection<T>) -> R
|
||||||
): Goal<R> = DynamicGoal(coroutineContext, this) {
|
): Goal<R> = DynamicGoal(coroutineContext, this) {
|
||||||
@ -105,7 +105,7 @@ fun <T, R> Collection<Goal<T>>.reduce(
|
|||||||
* @param T type of the input goal
|
* @param T type of the input goal
|
||||||
* @param R type of the result goal
|
* @param R type of the result goal
|
||||||
*/
|
*/
|
||||||
fun <K, T, R> Map<K, Goal<T>>.reduce(
|
public fun <K, T, R> Map<K, Goal<T>>.reduce(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
block: suspend CoroutineScope.(Map<K, T>) -> R
|
block: suspend CoroutineScope.(Map<K, T>) -> R
|
||||||
): Goal<R> = DynamicGoal(coroutineContext, this.values) {
|
): Goal<R> = DynamicGoal(coroutineContext, this.values) {
|
||||||
|
@ -19,10 +19,10 @@ import hep.dataforge.meta.Meta
|
|||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.string
|
import hep.dataforge.meta.string
|
||||||
|
|
||||||
interface GroupRule {
|
public interface GroupRule {
|
||||||
operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
|
public operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
|
||||||
|
|
||||||
companion object{
|
public companion object{
|
||||||
/**
|
/**
|
||||||
* Create grouping rule that creates groups for different values of value
|
* Create grouping rule that creates groups for different values of value
|
||||||
* field with name [key]
|
* field with name [key]
|
||||||
@ -31,7 +31,7 @@ interface GroupRule {
|
|||||||
* @param defaultTagValue
|
* @param defaultTagValue
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
public fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
||||||
GroupRule {
|
GroupRule {
|
||||||
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
|
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
|
||||||
val map = HashMap<String, DataTreeBuilder<T>>()
|
val map = HashMap<String, DataTreeBuilder<T>>()
|
||||||
@ -52,7 +52,7 @@ interface GroupRule {
|
|||||||
// def = "default",
|
// def = "default",
|
||||||
// info = "Default value which should be used for content in which the grouping value is not presented"
|
// info = "Default value which should be used for content in which the grouping value is not presented"
|
||||||
// )
|
// )
|
||||||
fun byMeta(config: Meta): GroupRule {
|
public fun byMeta(config: Meta): GroupRule {
|
||||||
//TODO expand grouping options
|
//TODO expand grouping options
|
||||||
return config["byValue"]?.string?.let {
|
return config["byValue"]?.string?.let {
|
||||||
byValue(
|
byValue(
|
||||||
|
@ -7,32 +7,31 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* Action environment includes data name, data meta and action configuration meta
|
* Action environment includes data name, data meta and action configuration meta
|
||||||
*/
|
*/
|
||||||
data class ActionEnv(
|
public data class ActionEnv(
|
||||||
val name: Name,
|
val name: Name,
|
||||||
val meta: Meta,
|
val meta: Meta,
|
||||||
val actionMeta: Meta
|
val actionMeta: Meta
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action environment
|
* Action environment
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class MapActionBuilder<T, R>(var name: Name, var meta: MetaBuilder, val actionMeta: Meta) {
|
public class MapActionBuilder<T, R>(public var name: Name, public var meta: MetaBuilder, public val actionMeta: Meta) {
|
||||||
lateinit var result: suspend ActionEnv.(T) -> R
|
public lateinit var result: suspend ActionEnv.(T) -> R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the result of goal
|
* Calculate the result of goal
|
||||||
*/
|
*/
|
||||||
fun result(f: suspend ActionEnv.(T) -> R) {
|
public fun result(f: suspend ActionEnv.(T) -> R) {
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MapAction<T : Any, out R : Any>(
|
public class MapAction<T : Any, out R : Any>(
|
||||||
val inputType: KClass<T>,
|
public val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
public val outputType: KClass<out R>,
|
||||||
private val block: MapActionBuilder<T, R>.() -> Unit
|
private val block: MapActionBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
@ -67,7 +66,7 @@ class MapAction<T : Any, out R : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any, reified R : Any> DataNode<T>.map(
|
public inline fun <reified T : Any, reified R : Any> DataNode<T>.map(
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
noinline action: MapActionBuilder<in T, out R>.() -> Unit
|
noinline action: MapActionBuilder<in T, out R>.() -> Unit
|
||||||
): DataNode<R> = MapAction(T::class, R::class, action).invoke(this, meta)
|
): DataNode<R> = MapAction(T::class, R::class, action).invoke(this, meta)
|
||||||
|
@ -7,25 +7,25 @@ import hep.dataforge.names.toName
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
class JoinGroup<T : Any, R : Any>(var name: String, internal val node: DataNode<T>) {
|
public class JoinGroup<T : Any, R : Any>(public var name: String, internal val node: DataNode<T>) {
|
||||||
|
|
||||||
var meta: MetaBuilder = MetaBuilder()
|
public var meta: MetaBuilder = MetaBuilder()
|
||||||
|
|
||||||
lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R
|
public lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R
|
||||||
|
|
||||||
fun result(f: suspend ActionEnv.(Map<Name, T>) -> R) {
|
public fun result(f: suspend ActionEnv.(Map<Name, T>) -> R) {
|
||||||
this.result = f;
|
this.result = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
public class ReduceGroupBuilder<T : Any, R : Any>(public val actionMeta: Meta) {
|
||||||
private val groupRules: MutableList<(DataNode<T>) -> List<JoinGroup<T, R>>> = ArrayList();
|
private val groupRules: MutableList<(DataNode<T>) -> List<JoinGroup<T, R>>> = ArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* introduce grouping by value name
|
* introduce grouping by value name
|
||||||
*/
|
*/
|
||||||
fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) {
|
public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) {
|
||||||
groupRules += { node ->
|
groupRules += { node ->
|
||||||
GroupRule.byValue(tag, defaultTag).invoke(node).map {
|
GroupRule.byValue(tag, defaultTag).invoke(node).map {
|
||||||
JoinGroup<T, R>(it.key, it.value).apply(action)
|
JoinGroup<T, R>(it.key, it.value).apply(action)
|
||||||
@ -36,7 +36,7 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
|||||||
/**
|
/**
|
||||||
* Add a single fixed group to grouping rules
|
* Add a single fixed group to grouping rules
|
||||||
*/
|
*/
|
||||||
fun group(groupName: String, filter: DataFilter, action: JoinGroup<T, R>.() -> Unit) {
|
public fun group(groupName: String, filter: DataFilter, action: JoinGroup<T, R>.() -> Unit) {
|
||||||
groupRules += { node ->
|
groupRules += { node ->
|
||||||
listOf(
|
listOf(
|
||||||
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
|
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
|
||||||
@ -44,7 +44,7 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun group(groupName: String, filter: (Name, Data<T>) -> Boolean, action: JoinGroup<T, R>.() -> Unit) {
|
public fun group(groupName: String, filter: (Name, Data<T>) -> Boolean, action: JoinGroup<T, R>.() -> Unit) {
|
||||||
groupRules += { node ->
|
groupRules += { node ->
|
||||||
listOf(
|
listOf(
|
||||||
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
|
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
|
||||||
@ -55,7 +55,7 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
|||||||
/**
|
/**
|
||||||
* Apply transformation to the whole node
|
* Apply transformation to the whole node
|
||||||
*/
|
*/
|
||||||
fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) {
|
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) {
|
||||||
groupRules += { node ->
|
groupRules += { node ->
|
||||||
listOf(JoinGroup<T, R>(resultName, node).apply { result(f) })
|
listOf(JoinGroup<T, R>(resultName, node).apply { result(f) })
|
||||||
}
|
}
|
||||||
@ -71,9 +71,9 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
|||||||
/**
|
/**
|
||||||
* The same rules as for KPipe
|
* The same rules as for KPipe
|
||||||
*/
|
*/
|
||||||
class ReduceAction<T : Any, R : Any>(
|
public class ReduceAction<T : Any, R : Any>(
|
||||||
val inputType: KClass<T>,
|
public val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
public val outputType: KClass<out R>,
|
||||||
private val action: ReduceGroupBuilder<T, R>.() -> Unit
|
private val action: ReduceGroupBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
@ -104,4 +104,4 @@ class ReduceAction<T : Any, R : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <T> Map<Name, T>.get(name: String) = get(name.toName())
|
public operator fun <T> Map<Name, T>.get(name: String): T? = get(name.toName())
|
||||||
|
@ -10,16 +10,16 @@ import kotlin.collections.set
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
class FragmentRule<T : Any, R : Any>(val name: Name, var meta: MetaBuilder) {
|
public class FragmentRule<T : Any, R : Any>(public val name: Name, public var meta: MetaBuilder) {
|
||||||
lateinit var result: suspend (T) -> R
|
public lateinit var result: suspend (T) -> R
|
||||||
|
|
||||||
fun result(f: suspend (T) -> R) {
|
public fun result(f: suspend (T) -> R) {
|
||||||
result = f;
|
result = f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SplitBuilder<T : Any, R : Any>(val name: Name, val meta: Meta) {
|
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()
|
internal val fragments: MutableMap<Name, FragmentRule<T, R>.() -> Unit> = HashMap()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,14 +27,14 @@ class SplitBuilder<T : Any, R : Any>(val name: Name, val meta: Meta) {
|
|||||||
* @param name the name of a fragment
|
* @param name the name of a fragment
|
||||||
* @param rule the rule to transform fragment name and meta using
|
* @param rule the rule to transform fragment name and meta using
|
||||||
*/
|
*/
|
||||||
fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) {
|
public fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) {
|
||||||
fragments[name.toName()] = rule
|
fragments[name.toName()] = rule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SplitAction<T : Any, R : Any>(
|
public class SplitAction<T : Any, R : Any>(
|
||||||
val inputType: KClass<T>,
|
public val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
public val outputType: KClass<out R>,
|
||||||
private val action: SplitBuilder<T, R>.() -> Unit
|
private val action: SplitBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
|
public fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
|
||||||
return object : Data<R> by this {
|
return object : Data<R> by this {
|
||||||
override val type: KClass<out R> = type
|
override val type: KClass<out R> = type
|
||||||
}
|
}
|
||||||
@ -15,19 +15,19 @@ fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
|
|||||||
/**
|
/**
|
||||||
* Safe upcast a [Data] to a supertype
|
* Safe upcast a [Data] to a supertype
|
||||||
*/
|
*/
|
||||||
inline fun <reified R : Any, T : R> Data<T>.upcast(): Data<R> = upcast(R::class)
|
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
|
* Check if node could be safely cast to given class
|
||||||
*/
|
*/
|
||||||
expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean
|
internal expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if data could be safely cast to given class
|
* Check if data could be safely cast to given class
|
||||||
*/
|
*/
|
||||||
expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean
|
internal expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean
|
||||||
|
|
||||||
fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
|
public fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
|
||||||
is DataItem.Node -> node.canCast(type)
|
is DataItem.Node -> node.canCast(type)
|
||||||
is DataItem.Leaf -> data.canCast(type)
|
is DataItem.Leaf -> data.canCast(type)
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
|
|||||||
* Unsafe cast of data node
|
* Unsafe cast of data node
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> {
|
public fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> {
|
||||||
return object : Data<R> {
|
return object : Data<R> {
|
||||||
override val meta: Meta get() = this@cast.meta
|
override val meta: Meta get() = this@cast.meta
|
||||||
override val dependencies: Collection<Goal<*>> get() = this@cast.dependencies
|
override val dependencies: Collection<Goal<*>> get() = this@cast.dependencies
|
||||||
@ -47,10 +47,10 @@ fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(R::class)
|
public inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(R::class)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <R : Any> DataNode<*>.cast(type: KClass<out R>): DataNode<R> {
|
public fun <R : Any> DataNode<*>.cast(type: KClass<out R>): DataNode<R> {
|
||||||
return object : DataNode<R> {
|
return object : DataNode<R> {
|
||||||
override val meta: Meta get() = this@cast.meta
|
override val meta: Meta get() = this@cast.meta
|
||||||
override val type: KClass<out R> = type
|
override val type: KClass<out R> = type
|
||||||
@ -58,12 +58,12 @@ fun <R : Any> DataNode<*>.cast(type: KClass<out R>): DataNode<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified R : Any> DataNode<*>.cast(): DataNode<R> = cast(R::class)
|
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
|
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||||
*/
|
*/
|
||||||
fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
|
public fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
|
||||||
if (!canCast(type)) {
|
if (!canCast(type)) {
|
||||||
error("$type expected, but $type received")
|
error("$type expected, but $type received")
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,10 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* Check that node is compatible with given type meaning that each element could be cast to the type
|
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||||
*/
|
*/
|
||||||
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
|
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
|
||||||
//Not supported in js yet
|
return this.type == type
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
|
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
|
||||||
//Not supported in js yet
|
return this.type == type
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* A zero-copy data node wrapper that returns only children with appropriate type.
|
* A zero-copy data node wrapper that returns only children with appropriate type.
|
||||||
*/
|
*/
|
||||||
class TypeFilteredDataNode<out T : Any>(val origin: DataNode<*>, override val type: KClass<out T>) : DataNode<T> {
|
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 meta: Meta get() = origin.meta
|
||||||
override val items: Map<NameToken, DataItem<T>> by lazy {
|
override val items: Map<NameToken, DataItem<T>> by lazy {
|
||||||
origin.items.mapNotNull { (key, item) ->
|
origin.items.mapNotNull { (key, item) ->
|
||||||
|
@ -3,33 +3,32 @@ package hep.dataforge.data
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.full.isSuperclassOf
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block the thread and get data content
|
* Block the thread and get data content
|
||||||
*/
|
*/
|
||||||
fun <T : Any> Data<T>.get(): T = runBlocking { await() }
|
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
|
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||||
*/
|
*/
|
||||||
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
|
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
|
||||||
type.isSuperclassOf(type)
|
type.isSubclassOf(this.type)
|
||||||
|
|
||||||
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
|
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
|
||||||
this.type.isSubclassOf(type)
|
this.type.isSubclassOf(type)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cast the node to given type if the cast is possible or return null
|
* Cast the node to given type if the cast is possible or return null
|
||||||
*/
|
*/
|
||||||
fun <R : Any> Data<*>.filterIsInstance(type: KClass<out R>): Data<R>? =
|
public fun <R : Any> Data<*>.filterIsInstance(type: KClass<out R>): Data<R>? =
|
||||||
if (canCast(type)) cast(type) else null
|
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],
|
* 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
|
* but could contain empty nodes
|
||||||
*/
|
*/
|
||||||
fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> {
|
public fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> {
|
||||||
return when {
|
return when {
|
||||||
canCast(type) -> cast(type)
|
canCast(type) -> cast(type)
|
||||||
this is TypeFilteredDataNode -> origin.filterIsInstance(type)
|
this is TypeFilteredDataNode -> origin.filterIsInstance(type)
|
||||||
@ -40,10 +39,10 @@ fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> {
|
|||||||
/**
|
/**
|
||||||
* Filter all elements of given data item that could be cast to given type. If no elements are available, return null.
|
* Filter all elements of given data item that could be cast to given type. If no elements are available, return null.
|
||||||
*/
|
*/
|
||||||
fun <R : Any> DataItem<*>?.filterIsInstance(type: KClass<out R>): DataItem<R>? = when (this) {
|
public fun <R : Any> DataItem<*>?.filterIsInstance(type: KClass<out R>): DataItem<R>? = when (this) {
|
||||||
null -> null
|
null -> null
|
||||||
is DataItem.Node -> DataItem.Node(this.node.filterIsInstance(type))
|
is DataItem.Node -> DataItem.Node(this.node.filterIsInstance(type))
|
||||||
is DataItem.Leaf -> this.data.filterIsInstance(type)?.let { DataItem.Leaf(it) }
|
is DataItem.Leaf -> this.data.filterIsInstance(type)?.let { DataItem.Leaf(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified R : Any> DataItem<*>?.filterIsInstance(): DataItem<R>? = this@filterIsInstance.filterIsInstance(R::class)
|
public inline fun <reified R : Any> DataItem<*>?.filterIsInstance(): DataItem<R>? = this@filterIsInstance.filterIsInstance(R::class)
|
@ -0,0 +1,14 @@
|
|||||||
|
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
|
||||||
|
}
|
469
dataforge-io/api/dataforge-io.api
Normal file
469
dataforge-io/api/dataforge-io.api
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
public final class hep/dataforge/io/BinaryMetaFormat : hep/dataforge/io/MetaFormat, hep/dataforge/io/MetaFormatFactory {
|
||||||
|
public static final field INSTANCE Lhep/dataforge/io/BinaryMetaFormat;
|
||||||
|
public fun getKey ()S
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getShortName ()Ljava/lang/String;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
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 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;
|
||||||
|
public fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
public final fun writeValue (Lkotlinx/io/Output;Lhep/dataforge/values/Value;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/BinaryView : kotlinx/io/Binary {
|
||||||
|
public fun <init> (Lkotlinx/io/Binary;II)V
|
||||||
|
public fun getSize ()I
|
||||||
|
public fun read (IILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/Consumer {
|
||||||
|
public abstract fun consume (Lhep/dataforge/io/Envelope;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/DoubleIOFormat : hep/dataforge/io/IOFormat, hep/dataforge/io/IOFormatFactory {
|
||||||
|
public static final field INSTANCE Lhep/dataforge/io/DoubleIOFormat;
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/IOFormat;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Ljava/lang/Double;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;D)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/Envelope {
|
||||||
|
public static final field Companion Lhep/dataforge/io/Envelope$Companion;
|
||||||
|
public abstract fun getData ()Lkotlinx/io/Binary;
|
||||||
|
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/Envelope$Companion {
|
||||||
|
public final fun getENVELOPE_DATA_ID_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getENVELOPE_DATA_TYPE_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getENVELOPE_DESCRIPTION_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getENVELOPE_NAME_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getENVELOPE_NODE_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getENVELOPE_TYPE_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/io/Envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeBuilder : hep/dataforge/io/Envelope {
|
||||||
|
public fun <init> ()V
|
||||||
|
public final fun data (Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public fun getData ()Lkotlinx/io/Binary;
|
||||||
|
public final fun getDataID ()Ljava/lang/String;
|
||||||
|
public final fun getDataType ()Ljava/lang/String;
|
||||||
|
public final fun getDescription ()Ljava/lang/String;
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getName ()Ljava/lang/String;
|
||||||
|
public final fun getType ()Ljava/lang/String;
|
||||||
|
public final fun meta (Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public final fun seal ()Lhep/dataforge/io/Envelope;
|
||||||
|
public fun setData (Lkotlinx/io/Binary;)V
|
||||||
|
public final fun setDataID (Ljava/lang/String;)V
|
||||||
|
public final fun setDataType (Ljava/lang/String;)V
|
||||||
|
public final fun setDescription (Ljava/lang/String;)V
|
||||||
|
public fun setMeta (Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun setName (Ljava/lang/String;)V
|
||||||
|
public final fun setType (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
public abstract fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public abstract fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public abstract fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeFormat$DefaultImpls {
|
||||||
|
public static fun getDefaultMetaFormat (Lhep/dataforge/io/EnvelopeFormat;)Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public static synthetic fun writeEnvelope$default (Lhep/dataforge/io/EnvelopeFormat;Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)V
|
||||||
|
public static fun writeObject (Lhep/dataforge/io/EnvelopeFormat;Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/EnvelopeFormatFactory : hep/dataforge/io/EnvelopeFormat, hep/dataforge/io/IOFormatFactory {
|
||||||
|
public static final field Companion Lhep/dataforge/io/EnvelopeFormatFactory$Companion;
|
||||||
|
public static final field ENVELOPE_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
public abstract fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public abstract fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public abstract fun peekFormat (Lhep/dataforge/io/IOPlugin;Lkotlinx/io/Input;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeFormatFactory$Companion {
|
||||||
|
public static final field ENVELOPE_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeFormatFactory$DefaultImpls {
|
||||||
|
public static fun getDefaultMetaFormat (Lhep/dataforge/io/EnvelopeFormatFactory;)Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public static fun getName (Lhep/dataforge/io/EnvelopeFormatFactory;)Lhep/dataforge/names/Name;
|
||||||
|
public static fun getType (Lhep/dataforge/io/EnvelopeFormatFactory;)Lkotlin/reflect/KClass;
|
||||||
|
public static fun toMeta (Lhep/dataforge/io/EnvelopeFormatFactory;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static fun writeObject (Lhep/dataforge/io/EnvelopeFormatFactory;Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeFormatKt {
|
||||||
|
public static final fun read (Lhep/dataforge/io/EnvelopeFormat;Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopeKt {
|
||||||
|
public static final fun contentEquals (Lhep/dataforge/io/Envelope;Lhep/dataforge/io/Envelope;)Z
|
||||||
|
public static final fun dataEquals (Lhep/dataforge/io/Envelope;Lhep/dataforge/io/Envelope;)Z
|
||||||
|
public static final fun getDataID (Lhep/dataforge/io/Envelope;)Ljava/lang/String;
|
||||||
|
public static final fun getDataType (Lhep/dataforge/io/Envelope;)Ljava/lang/String;
|
||||||
|
public static final fun getDescription (Lhep/dataforge/io/Envelope;)Ljava/lang/String;
|
||||||
|
public static final fun getType (Lhep/dataforge/io/Envelope;)Ljava/lang/String;
|
||||||
|
public static final fun metaEquals (Lhep/dataforge/io/Envelope;Lhep/dataforge/io/Envelope;)Z
|
||||||
|
public static final fun withMetaLayers (Lhep/dataforge/io/Envelope;[Lhep/dataforge/meta/Meta;)Lhep/dataforge/io/Envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopePart {
|
||||||
|
public fun <init> (Lkotlinx/io/Binary;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public final fun component1 ()Lkotlinx/io/Binary;
|
||||||
|
public final fun component2 ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun copy (Lkotlinx/io/Binary;Lhep/dataforge/meta/Meta;)Lhep/dataforge/io/EnvelopePart;
|
||||||
|
public static synthetic fun copy$default (Lhep/dataforge/io/EnvelopePart;Lkotlinx/io/Binary;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/io/EnvelopePart;
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getBinary ()Lkotlinx/io/Binary;
|
||||||
|
public final fun getDescription ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/EnvelopePartsKt {
|
||||||
|
public static final fun envelope (Lhep/dataforge/io/EnvelopePart;Lhep/dataforge/io/EnvelopeFormat;)Lhep/dataforge/io/Envelope;
|
||||||
|
public static final fun envelope (Lhep/dataforge/io/EnvelopePart;Lhep/dataforge/io/IOPlugin;)Lhep/dataforge/io/Envelope;
|
||||||
|
public static final fun envelopes (Lhep/dataforge/io/EnvelopeBuilder;Ljava/util/List;Lhep/dataforge/io/EnvelopeFormat;Ljava/lang/String;)V
|
||||||
|
public static synthetic fun envelopes$default (Lhep/dataforge/io/EnvelopeBuilder;Ljava/util/List;Lhep/dataforge/io/EnvelopeFormat;Ljava/lang/String;ILjava/lang/Object;)V
|
||||||
|
public static final fun getName (Lhep/dataforge/io/EnvelopePart;)Ljava/lang/String;
|
||||||
|
public static final fun multipart (Lhep/dataforge/io/EnvelopeBuilder;Ljava/util/List;Ljava/lang/String;)V
|
||||||
|
public static synthetic fun multipart$default (Lhep/dataforge/io/EnvelopeBuilder;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)V
|
||||||
|
public static final fun parts (Lhep/dataforge/io/Envelope;)Ljava/util/List;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/FileIOKt {
|
||||||
|
public static final fun append (Ljava/nio/file/Path;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public static final fun getDATA_FILE_NAME (Lhep/dataforge/io/IOPlugin$Companion;)Ljava/lang/String;
|
||||||
|
public static final fun getMETA_FILE_NAME (Lhep/dataforge/io/IOPlugin$Companion;)Ljava/lang/String;
|
||||||
|
public static final fun peekBinaryFormat (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public static final fun read (Ljava/nio/file/Path;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
|
public static final fun readEnvelope (Ljava/nio/file/Path;Lhep/dataforge/io/EnvelopeFormat;)Lhep/dataforge/io/Envelope;
|
||||||
|
public static final fun readEnvelopeFile (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;ZLkotlin/jvm/functions/Function2;)Lhep/dataforge/io/Envelope;
|
||||||
|
public static synthetic fun readEnvelopeFile$default (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lhep/dataforge/io/Envelope;
|
||||||
|
public static final fun readMetaFile (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/MetaFormat;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static synthetic fun readMetaFile$default (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/MetaFormat;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static final fun rewrite (Ljava/nio/file/Path;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public static final fun write (Ljava/nio/file/Path;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public static final fun writeEnvelopeDirectory (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;)V
|
||||||
|
public static synthetic fun writeEnvelopeDirectory$default (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;ILjava/lang/Object;)V
|
||||||
|
public static final fun writeEnvelopeFile (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/EnvelopeFormat;Lhep/dataforge/io/MetaFormatFactory;)V
|
||||||
|
public static synthetic fun writeEnvelopeFile$default (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/EnvelopeFormat;Lhep/dataforge/io/MetaFormatFactory;ILjava/lang/Object;)V
|
||||||
|
public static final fun writeMetaFile (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/meta/Meta;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public static synthetic fun writeMetaFile$default (Lhep/dataforge/io/IOPlugin;Ljava/nio/file/Path;Lhep/dataforge/meta/Meta;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)V
|
||||||
|
public static final fun writeToFile (Lhep/dataforge/io/IOFormat;Ljava/nio/file/Path;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/IOFormat : hep/dataforge/meta/MetaRepr {
|
||||||
|
public static final field Companion Lhep/dataforge/io/IOFormat$Companion;
|
||||||
|
public abstract fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public abstract fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOFormat$Companion {
|
||||||
|
public final fun getMETA_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
public final fun getNAME_KEY ()Lhep/dataforge/names/Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/IOFormatFactory : hep/dataforge/context/Factory, hep/dataforge/context/Named, hep/dataforge/meta/MetaRepr {
|
||||||
|
public static final field Companion Lhep/dataforge/io/IOFormatFactory$Companion;
|
||||||
|
public static final field IO_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public abstract fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOFormatFactory$Companion {
|
||||||
|
public static final field IO_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOFormatFactory$DefaultImpls {
|
||||||
|
public static fun toMeta (Lhep/dataforge/io/IOFormatFactory;)Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOFormatKt {
|
||||||
|
public static final fun fill (Lkotlinx/io/pool/ObjectPool;Lkotlin/jvm/functions/Function1;)Ljava/nio/ByteBuffer;
|
||||||
|
public static final fun readWith (Lkotlinx/io/Binary;Lhep/dataforge/io/IOFormat;)Ljava/lang/Object;
|
||||||
|
public static final fun readWith (Lkotlinx/io/Input;Lhep/dataforge/io/IOFormat;)Ljava/lang/Object;
|
||||||
|
public static final fun toBinary (Lhep/dataforge/io/IOFormat;Ljava/lang/Object;)Lkotlinx/io/Binary;
|
||||||
|
public static final fun writeWith (Lkotlinx/io/Output;Lhep/dataforge/io/IOFormat;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOPlugin : hep/dataforge/context/AbstractPlugin {
|
||||||
|
public static final field Companion Lhep/dataforge/io/IOPlugin$Companion;
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun content (Ljava/lang/String;)Ljava/util/Map;
|
||||||
|
public final fun getEnvelopeFormatFactories ()Ljava/util/Collection;
|
||||||
|
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 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;
|
||||||
|
public static synthetic fun resolveMetaFormat$default (Lhep/dataforge/io/IOPlugin;SLhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/io/MetaFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOPlugin$Companion : hep/dataforge/context/PluginFactory {
|
||||||
|
public final fun getDefaultEnvelopeFormats ()Ljava/util/List;
|
||||||
|
public final fun getDefaultMetaFormats ()Ljava/util/List;
|
||||||
|
public fun getTag ()Lhep/dataforge/context/PluginTag;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/IOPlugin;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IOPluginKt {
|
||||||
|
public static final fun getIo (Lhep/dataforge/context/Context;)Lhep/dataforge/io/IOPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/IoMiscKt {
|
||||||
|
public static final fun Binary (ILkotlin/jvm/functions/Function1;)Lkotlinx/io/Binary;
|
||||||
|
public static synthetic fun Binary$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/io/Binary;
|
||||||
|
public static final fun buildByteArray (ILkotlin/jvm/functions/Function1;)[B
|
||||||
|
public static synthetic fun buildByteArray$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)[B
|
||||||
|
public static final fun get (Lkotlinx/io/Binary;Lkotlin/ranges/IntRange;)Lhep/dataforge/io/BinaryView;
|
||||||
|
public static final fun readRawString (Lkotlinx/io/Input;I)Ljava/lang/String;
|
||||||
|
public static final fun view (Lkotlinx/io/Binary;II)Lhep/dataforge/io/BinaryView;
|
||||||
|
public static final fun writeRawString (Lkotlinx/io/Output;Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/JsonMetaFormat : hep/dataforge/io/MetaFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/JsonMetaFormat$Companion;
|
||||||
|
public fun <init> ()V
|
||||||
|
public fun <init> (Lkotlinx/serialization/json/Json;)V
|
||||||
|
public synthetic fun <init> (Lkotlinx/serialization/json/Json;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public fun readMeta (Lkotlinx/io/Input;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Meta;
|
||||||
|
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;
|
||||||
|
public fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/JsonMetaFormat$Companion : hep/dataforge/io/MetaFormatFactory {
|
||||||
|
public final fun getDEFAULT_JSON ()Lkotlinx/serialization/json/Json;
|
||||||
|
public fun getKey ()S
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getShortName ()Ljava/lang/String;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
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 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;
|
||||||
|
public fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/ListIOFormat : hep/dataforge/io/IOFormat {
|
||||||
|
public fun <init> (Lhep/dataforge/io/IOFormat;)V
|
||||||
|
public final fun getFormat ()Lhep/dataforge/io/IOFormat;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Ljava/util/List;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Ljava/util/List;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/MetaFormat : hep/dataforge/io/IOFormat {
|
||||||
|
public abstract fun readMeta (Lkotlinx/io/Input;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Meta;
|
||||||
|
public abstract fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/meta/Meta;
|
||||||
|
public abstract fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public abstract fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/MetaFormat$DefaultImpls {
|
||||||
|
public static synthetic fun readMeta$default (Lhep/dataforge/io/MetaFormat;Lkotlinx/io/Input;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static fun readObject (Lhep/dataforge/io/MetaFormat;Lkotlinx/io/Input;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static synthetic fun writeMeta$default (Lhep/dataforge/io/MetaFormat;Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)V
|
||||||
|
public static fun writeObject (Lhep/dataforge/io/MetaFormat;Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/MetaFormatFactory : hep/dataforge/io/IOFormatFactory, hep/dataforge/io/MetaFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/MetaFormatFactory$Companion;
|
||||||
|
public static final field META_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
public abstract fun getKey ()S
|
||||||
|
public abstract fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public abstract fun getShortName ()Ljava/lang/String;
|
||||||
|
public abstract fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public abstract fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/MetaFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/MetaFormatFactory$Companion {
|
||||||
|
public static final field META_FORMAT_TYPE Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/MetaFormatFactory$DefaultImpls {
|
||||||
|
public static fun getKey (Lhep/dataforge/io/MetaFormatFactory;)S
|
||||||
|
public static fun getName (Lhep/dataforge/io/MetaFormatFactory;)Lhep/dataforge/names/Name;
|
||||||
|
public static fun getType (Lhep/dataforge/io/MetaFormatFactory;)Lkotlin/reflect/KClass;
|
||||||
|
public static fun readObject (Lhep/dataforge/io/MetaFormatFactory;Lkotlinx/io/Input;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static fun toMeta (Lhep/dataforge/io/MetaFormatFactory;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static fun writeObject (Lhep/dataforge/io/MetaFormatFactory;Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/MetaFormatKt {
|
||||||
|
public static final fun parse (Lhep/dataforge/io/MetaFormat;Ljava/lang/String;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static final fun parse (Lhep/dataforge/io/MetaFormatFactory;Ljava/lang/String;Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Meta;
|
||||||
|
public static final fun toString (Lhep/dataforge/meta/Meta;Lhep/dataforge/io/MetaFormat;)Ljava/lang/String;
|
||||||
|
public static final fun toString (Lhep/dataforge/meta/Meta;Lhep/dataforge/io/MetaFormatFactory;)Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/PartialEnvelope {
|
||||||
|
public synthetic fun <init> (Lhep/dataforge/meta/Meta;ILkotlin/ULong;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public final fun component1 ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun component2-pVg5ArA ()I
|
||||||
|
public final fun component3-6VbMDqA ()Lkotlin/ULong;
|
||||||
|
public final fun copy-BMK4sig (Lhep/dataforge/meta/Meta;ILkotlin/ULong;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public static synthetic fun copy-BMK4sig$default (Lhep/dataforge/io/PartialEnvelope;Lhep/dataforge/meta/Meta;ILkotlin/ULong;ILjava/lang/Object;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
|
public final fun getDataOffset-pVg5ArA ()I
|
||||||
|
public final fun getDataSize-6VbMDqA ()Lkotlin/ULong;
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun hashCode ()I
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/ProxyEnvelope : hep/dataforge/io/Envelope {
|
||||||
|
public fun <init> (Lhep/dataforge/io/Envelope;[Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun getData ()Lkotlinx/io/Binary;
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Laminate;
|
||||||
|
public synthetic fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public final fun getSource ()Lhep/dataforge/io/Envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class hep/dataforge/io/Responder {
|
||||||
|
public abstract fun respond (Lhep/dataforge/io/Envelope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/SimpleEnvelope : hep/dataforge/io/Envelope {
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Meta;Lkotlinx/io/Binary;)V
|
||||||
|
public fun getData ()Lkotlinx/io/Binary;
|
||||||
|
public fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/StreamsIOKt {
|
||||||
|
public static final fun read (Ljava/io/InputStream;ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
|
public static final fun read (Ljava/io/InputStream;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
|
public static final fun readBlocking (Ljava/io/InputStream;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
|
public static final fun write (Ljava/io/OutputStream;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/TaggedEnvelopeFormat : hep/dataforge/io/EnvelopeFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/TaggedEnvelopeFormat$Companion;
|
||||||
|
public fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;)V
|
||||||
|
public synthetic fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public final fun getIo ()Lhep/dataforge/io/IOPlugin;
|
||||||
|
public final fun getVersion ()Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/TaggedEnvelopeFormat$Companion : hep/dataforge/io/EnvelopeFormatFactory {
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
public fun peekFormat (Lhep/dataforge/io/IOPlugin;Lkotlinx/io/Input;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/TaggedEnvelopeFormat$VERSION : java/lang/Enum {
|
||||||
|
public static final field DF02 Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;
|
||||||
|
public static final field DF03 Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;
|
||||||
|
public final fun getTagSize-pVg5ArA ()I
|
||||||
|
public static fun valueOf (Ljava/lang/String;)Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;
|
||||||
|
public static fun values ()[Lhep/dataforge/io/TaggedEnvelopeFormat$VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/TaglessEnvelopeFormat : hep/dataforge/io/EnvelopeFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/TaglessEnvelopeFormat$Companion;
|
||||||
|
public static final field DATA_LENGTH_PROPERTY Ljava/lang/String;
|
||||||
|
public static final field DATA_START_PROPERTY Ljava/lang/String;
|
||||||
|
public static final field DEFAULT_DATA_START Ljava/lang/String;
|
||||||
|
public static final field DEFAULT_META_START Ljava/lang/String;
|
||||||
|
public static final field META_LENGTH_PROPERTY Ljava/lang/String;
|
||||||
|
public static final field META_START_PROPERTY Ljava/lang/String;
|
||||||
|
public static final field META_TYPE_PROPERTY Ljava/lang/String;
|
||||||
|
public static final field TAGLESS_ENVELOPE_HEADER Ljava/lang/String;
|
||||||
|
public static final field TAGLESS_ENVELOPE_TYPE Ljava/lang/String;
|
||||||
|
public static final field code I
|
||||||
|
public fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/meta/Meta;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public final fun getIo ()Lhep/dataforge/io/IOPlugin;
|
||||||
|
public final fun getMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/TaglessEnvelopeFormat$Companion : hep/dataforge/io/EnvelopeFormatFactory {
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
public fun peekFormat (Lhep/dataforge/io/IOPlugin;Lkotlinx/io/Input;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/ValueIOFormat : hep/dataforge/io/IOFormat, hep/dataforge/io/IOFormatFactory {
|
||||||
|
public static final field INSTANCE Lhep/dataforge/io/ValueIOFormat;
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/IOFormat;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/values/Value;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/values/Value;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,17 @@
|
|||||||
import scientifik.DependencySourceSet.TEST
|
|
||||||
import scientifik.useSerialization
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("ru.mipt.npm.mpp")
|
||||||
|
id("ru.mipt.npm.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "IO module"
|
description = "IO module"
|
||||||
|
|
||||||
useSerialization(sourceSet = TEST){
|
kscience {
|
||||||
cbor()
|
useSerialization(sourceSet = ru.mipt.npm.gradle.DependencySourceSet.TEST) {
|
||||||
|
cbor()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ioVersion by rootProject.extra("0.2.0-npm-dev-7")
|
val ioVersion by rootProject.extra("0.2.0-npm-dev-11")
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
59
dataforge-io/dataforge-io-yaml/api/dataforge-io-yaml.api
Normal file
59
dataforge-io/dataforge-io-yaml/api/dataforge-io-yaml.api
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
public final class hep/dataforge/io/yaml/FrontMatterEnvelopeFormat : hep/dataforge/io/EnvelopeFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/yaml/FrontMatterEnvelopeFormat$Companion;
|
||||||
|
public static final field SEPARATOR Ljava/lang/String;
|
||||||
|
public fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun <init> (Lhep/dataforge/io/IOPlugin;Lhep/dataforge/meta/Meta;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/yaml/FrontMatterEnvelopeFormat$Companion : hep/dataforge/io/EnvelopeFormatFactory {
|
||||||
|
public fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
|
||||||
|
public fun peekFormat (Lhep/dataforge/io/IOPlugin;Lkotlinx/io/Input;)Lhep/dataforge/io/EnvelopeFormat;
|
||||||
|
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
|
||||||
|
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
|
||||||
|
public fun readPartial (Lkotlinx/io/Input;)Lhep/dataforge/io/PartialEnvelope;
|
||||||
|
public fun toMeta ()Lhep/dataforge/meta/Meta;
|
||||||
|
public fun writeEnvelope (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;Lhep/dataforge/io/MetaFormatFactory;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/io/Envelope;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/yaml/YamlMetaFormat : hep/dataforge/io/MetaFormat {
|
||||||
|
public static final field Companion Lhep/dataforge/io/yaml/YamlMetaFormat$Companion;
|
||||||
|
public fun <init> (Lhep/dataforge/meta/Meta;)V
|
||||||
|
public fun readMeta (Lkotlinx/io/Input;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Meta;
|
||||||
|
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;
|
||||||
|
public fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class hep/dataforge/io/yaml/YamlMetaFormat$Companion : hep/dataforge/io/MetaFormatFactory {
|
||||||
|
public fun getKey ()S
|
||||||
|
public fun getName ()Lhep/dataforge/names/Name;
|
||||||
|
public fun getShortName ()Ljava/lang/String;
|
||||||
|
public fun getType ()Lkotlin/reflect/KClass;
|
||||||
|
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 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;
|
||||||
|
public fun writeMeta (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
|
||||||
|
public fun writeObject (Lkotlinx/io/Output;Lhep/dataforge/meta/Meta;)V
|
||||||
|
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,13 @@
|
|||||||
import scientifik.useSerialization
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.jvm")
|
id("ru.mipt.npm.jvm")
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "YAML meta IO"
|
description = "YAML meta IO"
|
||||||
|
|
||||||
useSerialization{
|
kscience {
|
||||||
yaml()
|
useSerialization {
|
||||||
|
yaml()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
75
dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt
75
dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt
@ -9,20 +9,19 @@ import hep.dataforge.meta.Meta
|
|||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
import kotlinx.io.text.readUtf8Line
|
import kotlinx.io.text.readUtf8Line
|
||||||
import kotlinx.io.text.writeUtf8String
|
import kotlinx.io.text.writeUtf8String
|
||||||
import kotlinx.serialization.toUtf8Bytes
|
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
class FrontMatterEnvelopeFormat(
|
public class FrontMatterEnvelopeFormat(
|
||||||
val io: IOPlugin,
|
private val io: IOPlugin,
|
||||||
val meta: Meta = Meta.EMPTY
|
private val meta: Meta = Meta.EMPTY,
|
||||||
) : EnvelopeFormat {
|
) : EnvelopeFormat {
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope {
|
override fun readPartial(input: Input): PartialEnvelope {
|
||||||
var line: String = ""
|
var line = ""
|
||||||
var offset = 0u
|
var offset = 0u
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line() //?: error("Input does not contain front matter separator")
|
line = input.readUtf8Line() //?: error("Input does not contain front matter separator")
|
||||||
offset += line.toUtf8Bytes().size.toUInt()
|
offset += line.toByteArray().size.toUInt()
|
||||||
} while (!line.startsWith(SEPARATOR))
|
} while (!line.startsWith(SEPARATOR))
|
||||||
|
|
||||||
val readMetaFormat =
|
val readMetaFormat =
|
||||||
@ -32,22 +31,21 @@ class FrontMatterEnvelopeFormat(
|
|||||||
//TODO replace by preview
|
//TODO replace by preview
|
||||||
val meta = Binary {
|
val meta = Binary {
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line()
|
line = input.readUtf8Line()
|
||||||
writeUtf8String(line + "\r\n")
|
writeUtf8String(line + "\r\n")
|
||||||
offset += line.toUtf8Bytes().size.toUInt()
|
offset += line.toByteArray().size.toUInt()
|
||||||
} while (!line.startsWith(SEPARATOR))
|
} while (!line.startsWith(SEPARATOR))
|
||||||
}.read {
|
}.read {
|
||||||
readMetaFormat.run {
|
readMetaFormat.readMeta(input)
|
||||||
readMeta()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return PartialEnvelope(meta, offset, null)
|
return PartialEnvelope(meta, offset, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope {
|
override fun readObject(input: Input): Envelope {
|
||||||
var line: String = ""
|
var line = ""
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line() //?: error("Input does not contain front matter separator")
|
line = input.readUtf8Line() //?: error("Input does not contain front matter separator")
|
||||||
} while (!line.startsWith(SEPARATOR))
|
} while (!line.startsWith(SEPARATOR))
|
||||||
|
|
||||||
val readMetaFormat =
|
val readMetaFormat =
|
||||||
@ -56,26 +54,29 @@ class FrontMatterEnvelopeFormat(
|
|||||||
|
|
||||||
val meta = Binary {
|
val meta = Binary {
|
||||||
do {
|
do {
|
||||||
writeUtf8String(readUtf8Line() + "\r\n")
|
writeUtf8String(input.readUtf8Line() + "\r\n")
|
||||||
} while (!line.startsWith(SEPARATOR))
|
} while (!line.startsWith(SEPARATOR))
|
||||||
}.read {
|
}.read {
|
||||||
readMetaFormat.run {
|
readMetaFormat.readMeta(input)
|
||||||
readMeta()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val bytes = readByteArray()
|
val bytes = input.readByteArray()
|
||||||
val data = bytes.asBinary()
|
val data = bytes.asBinary()
|
||||||
return SimpleEnvelope(meta, data)
|
return SimpleEnvelope(meta, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
override fun writeEnvelope(
|
||||||
val metaFormat = metaFormatFactory(formatMeta, io.context)
|
output: Output,
|
||||||
writeRawString("$SEPARATOR\r\n")
|
envelope: Envelope,
|
||||||
metaFormat.run { writeObject(envelope.meta) }
|
metaFormatFactory: MetaFormatFactory,
|
||||||
writeRawString("$SEPARATOR\r\n")
|
formatMeta: Meta,
|
||||||
|
) {
|
||||||
|
val metaFormat = metaFormatFactory(formatMeta, this@FrontMatterEnvelopeFormat.io.context)
|
||||||
|
output.writeRawString("${hep.dataforge.io.yaml.FrontMatterEnvelopeFormat.Companion.SEPARATOR}\r\n")
|
||||||
|
metaFormat.run { this.writeObject(output, envelope.meta) }
|
||||||
|
output.writeRawString("${hep.dataforge.io.yaml.FrontMatterEnvelopeFormat.Companion.SEPARATOR}\r\n")
|
||||||
//Printing data
|
//Printing data
|
||||||
envelope.data?.let { data ->
|
envelope.data?.let { data ->
|
||||||
writeBinary(data)
|
output.writeBinary(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +85,8 @@ class FrontMatterEnvelopeFormat(
|
|||||||
META_KEY put meta
|
META_KEY put meta
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : EnvelopeFormatFactory {
|
public companion object : EnvelopeFormatFactory {
|
||||||
const val SEPARATOR = "---"
|
public const val SEPARATOR = "---"
|
||||||
|
|
||||||
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
|
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
|
||||||
|
|
||||||
@ -106,14 +107,18 @@ class FrontMatterEnvelopeFormat(
|
|||||||
|
|
||||||
private val default by lazy { invoke() }
|
private val default by lazy { invoke() }
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope =
|
override fun readPartial(input: Input): PartialEnvelope =
|
||||||
default.run { readPartial() }
|
default.readPartial(input)
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) =
|
override fun writeEnvelope(
|
||||||
default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) }
|
output: Output,
|
||||||
|
envelope: Envelope,
|
||||||
|
metaFormatFactory: MetaFormatFactory,
|
||||||
|
formatMeta: Meta,
|
||||||
|
): Unit = default.writeEnvelope(output, envelope, metaFormatFactory, formatMeta)
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope =
|
|
||||||
default.run { readObject() }
|
override fun readObject(input: Input): Envelope = default.readObject(input)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,17 +16,20 @@ import kotlinx.io.asInputStream
|
|||||||
import kotlinx.io.text.writeUtf8String
|
import kotlinx.io.text.writeUtf8String
|
||||||
import org.yaml.snakeyaml.Yaml
|
import org.yaml.snakeyaml.Yaml
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent meta as Yaml
|
||||||
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
class YamlMetaFormat(val meta: Meta) : MetaFormat {
|
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
|
||||||
private val yaml = Yaml()
|
private val yaml = Yaml()
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
|
||||||
val string = yaml.dump(meta.toMap(descriptor))
|
val string = yaml.dump(meta.toMap(descriptor))
|
||||||
writeUtf8String(string)
|
output.writeUtf8String(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||||
val map: Map<String, Any?> = yaml.load(asInputStream())
|
val map: Map<String, Any?> = yaml.load(input.asInputStream())
|
||||||
return map.toMeta(descriptor)
|
return map.toMeta(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,19 +38,19 @@ class YamlMetaFormat(val meta: Meta) : MetaFormat {
|
|||||||
META_KEY put meta
|
META_KEY put meta
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : MetaFormatFactory {
|
public companion object : MetaFormatFactory {
|
||||||
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
|
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
|
||||||
|
|
||||||
override val shortName = "yaml"
|
override val shortName: String = "yaml"
|
||||||
|
|
||||||
override val key: Short = 0x594d //YM
|
override val key: Short = 0x594d //YM
|
||||||
|
|
||||||
private val default = YamlMetaFormat()
|
private val default = YamlMetaFormat()
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) =
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
||||||
default.run { writeMeta(meta, descriptor) }
|
default.writeMeta(output, meta, descriptor)
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta =
|
override fun readMeta(input: kotlinx.io.Input, descriptor: NodeDescriptor?): Meta =
|
||||||
default.run { readMeta(descriptor) }
|
default.readMeta(input, descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,14 +11,18 @@ import kotlinx.io.*
|
|||||||
import kotlinx.io.text.readUtf8String
|
import kotlinx.io.text.readUtf8String
|
||||||
import kotlinx.io.text.writeUtf8String
|
import kotlinx.io.text.writeUtf8String
|
||||||
|
|
||||||
object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
/**
|
||||||
|
* A DataForge-specific simplified binary format for meta
|
||||||
|
* TODO add description
|
||||||
|
*/
|
||||||
|
public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
||||||
override val shortName: String = "bin"
|
override val shortName: String = "bin"
|
||||||
override val key: Short = 0x4249//BI
|
override val key: Short = 0x4249//BI
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): MetaFormat = this
|
override fun invoke(meta: Meta, context: Context): MetaFormat = this
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||||
return (readMetaItem() as MetaItem.NodeItem).node
|
return (input.readMetaItem() as MetaItem.NodeItem).node
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Output.writeChar(char: Char) = writeByte(char.toByte())
|
private fun Output.writeChar(char: Char) = writeByte(char.toByte())
|
||||||
@ -28,7 +32,7 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
|||||||
writeUtf8String(str)
|
writeUtf8String(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Output.writeValue(value: Value) {
|
public fun Output.writeValue(value: Value) {
|
||||||
if (value.isList()) {
|
if (value.isList()) {
|
||||||
writeChar('L')
|
writeChar('L')
|
||||||
writeInt(value.list.size)
|
writeInt(value.list.size)
|
||||||
@ -75,17 +79,21 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
override fun writeMeta(
|
||||||
writeChar('M')
|
output: kotlinx.io.Output,
|
||||||
writeInt(meta.items.size)
|
meta: hep.dataforge.meta.Meta,
|
||||||
|
descriptor: hep.dataforge.meta.descriptors.NodeDescriptor?
|
||||||
|
) {
|
||||||
|
output.writeChar('M')
|
||||||
|
output.writeInt(meta.items.size)
|
||||||
meta.items.forEach { (key, item) ->
|
meta.items.forEach { (key, item) ->
|
||||||
writeString(key.toString())
|
output.writeString(key.toString())
|
||||||
when (item) {
|
when (item) {
|
||||||
is MetaItem.ValueItem -> {
|
is MetaItem.ValueItem -> {
|
||||||
writeValue(item.value)
|
output.writeValue(item.value)
|
||||||
}
|
}
|
||||||
is MetaItem.NodeItem -> {
|
is MetaItem.NodeItem -> {
|
||||||
writeObject(item.node)
|
writeObject(output, item.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +105,7 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
public fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
||||||
return when (val keyChar = readByte().toChar()) {
|
return when (val keyChar = readByte().toChar()) {
|
||||||
'S' -> MetaItem.ValueItem(StringValue(readString()))
|
'S' -> MetaItem.ValueItem(StringValue(readString()))
|
||||||
'N' -> MetaItem.ValueItem(Null)
|
'N' -> MetaItem.ValueItem(Null)
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package hep.dataforge.io
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fire-and-forget consumer of messages
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public interface Consumer {
|
||||||
|
public fun consume(message: Envelope): Unit
|
||||||
|
}
|
@ -4,64 +4,66 @@ import hep.dataforge.meta.Laminate
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.string
|
import hep.dataforge.meta.string
|
||||||
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import kotlinx.io.Binary
|
import kotlinx.io.Binary
|
||||||
|
|
||||||
interface Envelope {
|
public interface Envelope {
|
||||||
val meta: Meta
|
public val meta: Meta
|
||||||
val data: Binary?
|
public val data: Binary?
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta keys
|
* meta keys
|
||||||
*/
|
*/
|
||||||
val ENVELOPE_NODE_KEY = "@envelope".asName()
|
public val ENVELOPE_NODE_KEY: Name = "@envelope".asName()
|
||||||
val ENVELOPE_TYPE_KEY = ENVELOPE_NODE_KEY + "type"
|
public val ENVELOPE_TYPE_KEY: Name = ENVELOPE_NODE_KEY + "type"
|
||||||
val ENVELOPE_DATA_TYPE_KEY = ENVELOPE_NODE_KEY + "dataType"
|
public val ENVELOPE_DATA_TYPE_KEY: Name = ENVELOPE_NODE_KEY + "dataType"
|
||||||
val ENVELOPE_DATA_ID_KEY = ENVELOPE_NODE_KEY + "dataID"
|
public val ENVELOPE_DATA_ID_KEY: Name = ENVELOPE_NODE_KEY + "dataID"
|
||||||
val ENVELOPE_DESCRIPTION_KEY = ENVELOPE_NODE_KEY + "description"
|
public val ENVELOPE_DESCRIPTION_KEY: Name = ENVELOPE_NODE_KEY + "description"
|
||||||
val ENVELOPE_NAME_KEY = ENVELOPE_NODE_KEY + "name"
|
public val ENVELOPE_NAME_KEY: Name = ENVELOPE_NODE_KEY + "name"
|
||||||
//const val ENVELOPE_TIME_KEY = "@envelope.time"
|
//const val ENVELOPE_TIME_KEY = "@envelope.time"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a static envelope using provided builder
|
* Build a static envelope using provided builder
|
||||||
*/
|
*/
|
||||||
inline operator fun invoke(block: EnvelopeBuilder.() -> Unit) = EnvelopeBuilder().apply(block).build()
|
public inline operator fun invoke(block: EnvelopeBuilder.() -> Unit): Envelope =
|
||||||
|
EnvelopeBuilder().apply(block).seal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleEnvelope(override val meta: Meta, override val data: Binary?) : Envelope
|
public class SimpleEnvelope(override val meta: Meta, override val data: Binary?) : Envelope
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The purpose of the envelope
|
* The purpose of the envelope
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
val Envelope.type: String? get() = meta[Envelope.ENVELOPE_TYPE_KEY].string
|
public val Envelope.type: String? get() = meta[Envelope.ENVELOPE_TYPE_KEY].string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of data encoding
|
* The type of data encoding
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
val Envelope.dataType: String? get() = meta[Envelope.ENVELOPE_DATA_TYPE_KEY].string
|
public val Envelope.dataType: String? get() = meta[Envelope.ENVELOPE_DATA_TYPE_KEY].string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Textual user friendly description
|
* Textual user friendly description
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
val Envelope.description: String? get() = meta[Envelope.ENVELOPE_DESCRIPTION_KEY].string
|
public val Envelope.description: String? get() = meta[Envelope.ENVELOPE_DESCRIPTION_KEY].string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional unique identifier that is used for data comparison. Data without identifier could not be compared to another data.
|
* An optional unique identifier that is used for data comparison. Data without identifier could not be compared to another data.
|
||||||
*/
|
*/
|
||||||
val Envelope.dataID: String? get() = meta[Envelope.ENVELOPE_DATA_ID_KEY].string
|
public val Envelope.dataID: String? get() = meta[Envelope.ENVELOPE_DATA_ID_KEY].string
|
||||||
|
|
||||||
fun Envelope.metaEquals(other: Envelope): Boolean = this.meta == other.meta
|
public fun Envelope.metaEquals(other: Envelope): Boolean = this.meta == other.meta
|
||||||
|
|
||||||
fun Envelope.dataEquals(other: Envelope): Boolean = this.dataID != null && this.dataID == other.dataID
|
public fun Envelope.dataEquals(other: Envelope): Boolean = this.dataID != null && this.dataID == other.dataID
|
||||||
|
|
||||||
fun Envelope.contentEquals(other: Envelope): Boolean {
|
public fun Envelope.contentEquals(other: Envelope): Boolean {
|
||||||
return (this === other || (metaEquals(other) && dataEquals(other)))
|
return (this === other || (metaEquals(other) && dataEquals(other)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ fun Envelope.contentEquals(other: Envelope): Boolean {
|
|||||||
/**
|
/**
|
||||||
* An envelope, which wraps existing envelope and adds one or several additional layers of meta
|
* An envelope, which wraps existing envelope and adds one or several additional layers of meta
|
||||||
*/
|
*/
|
||||||
class ProxyEnvelope(val source: Envelope, vararg meta: Meta) : Envelope {
|
public class ProxyEnvelope(public val source: Envelope, vararg meta: Meta) : Envelope {
|
||||||
override val meta: Laminate = Laminate(*meta, source.meta)
|
override val meta: Laminate = Laminate(*meta, source.meta)
|
||||||
override val data: Binary? get() = source.data
|
override val data: Binary? get() = source.data
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ class ProxyEnvelope(val source: Envelope, vararg meta: Meta) : Envelope {
|
|||||||
/**
|
/**
|
||||||
* Add few meta layers to existing envelope (on top of existing meta)
|
* Add few meta layers to existing envelope (on top of existing meta)
|
||||||
*/
|
*/
|
||||||
fun Envelope.withMetaLayers(vararg layers: Meta): Envelope {
|
public fun Envelope.withMetaLayers(vararg layers: Meta): Envelope {
|
||||||
return when {
|
return when {
|
||||||
layers.isEmpty() -> this
|
layers.isEmpty() -> this
|
||||||
this is ProxyEnvelope -> ProxyEnvelope(source, *layers, *this.meta.layers.toTypedArray())
|
this is ProxyEnvelope -> ProxyEnvelope(source, *layers, *this.meta.layers.toTypedArray())
|
||||||
|
@ -3,42 +3,44 @@ package hep.dataforge.io
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
|
|
||||||
class EnvelopeBuilder {
|
public class EnvelopeBuilder : Envelope {
|
||||||
private val metaBuilder = MetaBuilder()
|
private val metaBuilder = MetaBuilder()
|
||||||
var data: Binary? = null
|
|
||||||
|
|
||||||
fun meta(block: MetaBuilder.() -> Unit) {
|
override var data: Binary? = null
|
||||||
|
override var meta: Meta
|
||||||
|
get() = metaBuilder
|
||||||
|
set(value) {
|
||||||
|
metaBuilder.update(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun meta(block: MetaBuilder.() -> Unit) {
|
||||||
metaBuilder.apply(block)
|
metaBuilder.apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun meta(meta: Meta) {
|
|
||||||
metaBuilder.update(meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The general purpose of the envelope
|
* The general purpose of the envelope
|
||||||
*/
|
*/
|
||||||
var type by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
|
public var type: String? by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
|
||||||
var dataType by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
|
public var dataType: String? by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data unique identifier to bypass identity checks
|
* Data unique identifier to bypass identity checks
|
||||||
*/
|
*/
|
||||||
var dataID by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
|
public var dataID: String? by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
|
||||||
var description by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
|
public var description: String? by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
|
||||||
var name by metaBuilder.string(key = Envelope.ENVELOPE_NAME_KEY)
|
public var name: String? by metaBuilder.string(key = Envelope.ENVELOPE_NAME_KEY)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a data binary from given builder
|
* Construct a data binary from given builder
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalIoApi::class)
|
@OptIn(ExperimentalIoApi::class)
|
||||||
fun data(block: Output.() -> Unit) {
|
public fun data(block: Output.() -> Unit) {
|
||||||
val arrayBuilder = ByteArrayOutput()
|
val arrayBuilder = ByteArrayOutput()
|
||||||
arrayBuilder.block()
|
arrayBuilder.block()
|
||||||
data = arrayBuilder.toByteArray().asBinary()
|
data = arrayBuilder.toByteArray().asBinary()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build() = SimpleEnvelope(metaBuilder.seal(), data)
|
public fun seal(): Envelope = SimpleEnvelope(metaBuilder.seal(), data)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,31 +13,29 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* A partially read envelope with meta, but without data
|
* A partially read envelope with meta, but without data
|
||||||
*/
|
*/
|
||||||
@ExperimentalUnsignedTypes
|
public data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: ULong?)
|
||||||
data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: ULong?)
|
|
||||||
|
|
||||||
interface EnvelopeFormat : IOFormat<Envelope> {
|
public interface EnvelopeFormat : IOFormat<Envelope> {
|
||||||
val defaultMetaFormat: MetaFormatFactory get() = JsonMetaFormat
|
public val defaultMetaFormat: MetaFormatFactory get() = JsonMetaFormat
|
||||||
|
|
||||||
fun Input.readPartial(): PartialEnvelope
|
public fun readPartial(input: Input): PartialEnvelope
|
||||||
|
|
||||||
fun Output.writeEnvelope(
|
public fun writeEnvelope(
|
||||||
|
output: Output,
|
||||||
envelope: Envelope,
|
envelope: Envelope,
|
||||||
metaFormatFactory: MetaFormatFactory = defaultMetaFormat,
|
metaFormatFactory: MetaFormatFactory = defaultMetaFormat,
|
||||||
formatMeta: Meta = Meta.EMPTY
|
formatMeta: Meta = Meta.EMPTY,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope
|
override fun readObject(input: Input): Envelope
|
||||||
|
|
||||||
override fun Output.writeObject(obj: Envelope): Unit = writeEnvelope(obj)
|
override fun writeObject(output: Output, obj: Envelope): Unit = writeEnvelope(output, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EnvelopeFormat.readPartial(input: Input) = input.readPartial()
|
public fun EnvelopeFormat.read(input: Input): Envelope = readObject(input)
|
||||||
|
|
||||||
fun EnvelopeFormat.read(input: Input) = input.readObject()
|
|
||||||
|
|
||||||
@Type(ENVELOPE_FORMAT_TYPE)
|
@Type(ENVELOPE_FORMAT_TYPE)
|
||||||
interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
|
public interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
|
||||||
override val name: Name get() = "envelope".asName()
|
override val name: Name get() = "envelope".asName()
|
||||||
override val type: KClass<out Envelope> get() = Envelope::class
|
override val type: KClass<out Envelope> get() = Envelope::class
|
||||||
|
|
||||||
@ -47,9 +45,9 @@ interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
|
|||||||
* Try to infer specific format from input and return null if the attempt is failed.
|
* Try to infer specific format from input and return null if the attempt is failed.
|
||||||
* This method does **not** return Input into initial state.
|
* This method does **not** return Input into initial state.
|
||||||
*/
|
*/
|
||||||
fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat?
|
public fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat?
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val ENVELOPE_FORMAT_TYPE = "io.format.envelope"
|
public const val ENVELOPE_FORMAT_TYPE: String = "io.format.envelope"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,11 +31,11 @@ private class PartDescriptor : Scheme() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class EnvelopePart(val binary: Binary, val description: Meta?)
|
public data class EnvelopePart(val binary: Binary, val description: Meta?)
|
||||||
|
|
||||||
typealias EnvelopeParts = List<EnvelopePart>
|
public typealias EnvelopeParts = List<EnvelopePart>
|
||||||
|
|
||||||
fun EnvelopeBuilder.multipart(
|
public fun EnvelopeBuilder.multipart(
|
||||||
parts: EnvelopeParts,
|
parts: EnvelopeParts,
|
||||||
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
||||||
) {
|
) {
|
||||||
@ -69,7 +69,7 @@ fun EnvelopeBuilder.multipart(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EnvelopeBuilder.envelopes(
|
public fun EnvelopeBuilder.envelopes(
|
||||||
envelopes: List<Envelope>,
|
envelopes: List<Envelope>,
|
||||||
format: EnvelopeFormat = TaggedEnvelopeFormat,
|
format: EnvelopeFormat = TaggedEnvelopeFormat,
|
||||||
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
||||||
@ -84,11 +84,11 @@ fun EnvelopeBuilder.envelopes(
|
|||||||
multipart(parts, separator)
|
multipart(parts, separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Envelope.parts(): EnvelopeParts {
|
public fun Envelope.parts(): EnvelopeParts {
|
||||||
if (data == null) return emptyList()
|
if (data == null) return emptyList()
|
||||||
//TODO add zip folder reader
|
//TODO add zip folder reader
|
||||||
val parts = meta.getIndexed(PARTS_KEY).values.mapNotNull { it.node }.map {
|
val parts = meta.getIndexed(PARTS_KEY).values.mapNotNull { it.node }.map {
|
||||||
PartDescriptor.wrap(it)
|
PartDescriptor.read(it)
|
||||||
}
|
}
|
||||||
return if (parts.isEmpty()) {
|
return if (parts.isEmpty()) {
|
||||||
listOf(EnvelopePart(data!!, meta[MULTIPART_KEY].node))
|
listOf(EnvelopePart(data!!, meta[MULTIPART_KEY].node))
|
||||||
@ -101,14 +101,14 @@ fun Envelope.parts(): EnvelopeParts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EnvelopePart.envelope(format: EnvelopeFormat): Envelope = binary.readWith(format)
|
public fun EnvelopePart.envelope(format: EnvelopeFormat): Envelope = binary.readWith(format)
|
||||||
|
|
||||||
val EnvelopePart.name: String? get() = description?.get("name").string
|
public val EnvelopePart.name: String? get() = description?.get("name").string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent envelope part by an envelope
|
* Represent envelope part by an envelope
|
||||||
*/
|
*/
|
||||||
fun EnvelopePart.envelope(plugin: IOPlugin): Envelope {
|
public fun EnvelopePart.envelope(plugin: IOPlugin): Envelope {
|
||||||
val formatItem = description?.get(PART_FORMAT_KEY)
|
val formatItem = description?.get(PART_FORMAT_KEY)
|
||||||
return if (formatItem != null) {
|
return if (formatItem != null) {
|
||||||
val format: EnvelopeFormat = plugin.resolveEnvelopeFormat(formatItem)
|
val format: EnvelopeFormat = plugin.resolveEnvelopeFormat(formatItem)
|
||||||
|
@ -20,41 +20,42 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* And interface for reading and writing objects into with IO streams
|
* And interface for reading and writing objects into with IO streams
|
||||||
*/
|
*/
|
||||||
interface IOFormat<T : Any> : MetaRepr {
|
public interface IOFormat<T : Any> : MetaRepr {
|
||||||
fun Output.writeObject(obj: T)
|
public fun writeObject(output: Output, obj: T)
|
||||||
fun Input.readObject(): T
|
public fun readObject(input: Input): T
|
||||||
|
|
||||||
companion object{
|
public companion object {
|
||||||
val NAME_KEY = "name".asName()
|
public val NAME_KEY: Name = "name".asName()
|
||||||
val META_KEY = "meta".asName()
|
public val META_KEY: Name = "meta".asName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> Input.readWith(format: IOFormat<T>): T = format.run { readObject() }
|
public fun <T : Any> Input.readWith(format: IOFormat<T>): T = format.readObject(this@readWith)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read given binary as object using given format
|
* Read given binary as object using given format
|
||||||
*/
|
*/
|
||||||
fun <T : Any> Binary.readWith(format: IOFormat<T>): T = read {
|
public fun <T : Any> Binary.readWith(format: IOFormat<T>): T = read {
|
||||||
readWith(format)
|
readWith(format)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> Output.writeWith(format: IOFormat<T>, obj: T) = format.run { writeObject(obj) }
|
public fun <T : Any> Output.writeWith(format: IOFormat<T>, obj: T): Unit =
|
||||||
|
format.run { writeObject(this@writeWith, obj) }
|
||||||
|
|
||||||
class ListIOFormat<T : Any>(val format: IOFormat<T>) : IOFormat<List<T>> {
|
public class ListIOFormat<T : Any>(public val format: IOFormat<T>) : IOFormat<List<T>> {
|
||||||
override fun Output.writeObject(obj: List<T>) {
|
override fun writeObject(output: Output, obj: List<T>) {
|
||||||
writeInt(obj.size)
|
output.writeInt(obj.size)
|
||||||
format.run {
|
this.format.run {
|
||||||
obj.forEach {
|
obj.forEach {
|
||||||
writeObject(it)
|
writeObject(output, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): List<T> {
|
override fun readObject(input: Input): List<T> {
|
||||||
val size = readInt()
|
val size = input.readInt()
|
||||||
return format.run {
|
return format.run {
|
||||||
List(size) { readObject() }
|
List(size) { readObject(input) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,9 +65,9 @@ class ListIOFormat<T : Any>(val format: IOFormat<T>) : IOFormat<List<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val <T : Any> IOFormat<T>.list get() = ListIOFormat(this)
|
//public val <T : Any> IOFormat<T>.list: ListIOFormat<T> get() = ListIOFormat(this)
|
||||||
|
|
||||||
fun ObjectPool<Buffer>.fill(block: Buffer.() -> Unit): Buffer {
|
public fun ObjectPool<Buffer>.fill(block: Buffer.() -> Unit): Buffer {
|
||||||
val buffer = borrow()
|
val buffer = borrow()
|
||||||
return try {
|
return try {
|
||||||
buffer.apply(block)
|
buffer.apply(block)
|
||||||
@ -77,50 +78,50 @@ fun ObjectPool<Buffer>.fill(block: Buffer.() -> Unit): Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Type(IO_FORMAT_TYPE)
|
@Type(IO_FORMAT_TYPE)
|
||||||
interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named, MetaRepr {
|
public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named, MetaRepr {
|
||||||
/**
|
/**
|
||||||
* Explicit type for dynamic type checks
|
* Explicit type for dynamic type checks
|
||||||
*/
|
*/
|
||||||
val type: KClass<out T>
|
public val type: KClass<out T>
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
NAME_KEY put name.toString()
|
NAME_KEY put name.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val IO_FORMAT_TYPE = "io.format"
|
public const val IO_FORMAT_TYPE: String = "io.format"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> IOFormat<T>.toBinary(obj: T): Binary = Binary { writeObject(obj) }
|
public fun <T : Any> IOFormat<T>.toBinary(obj: T): Binary = Binary { writeObject(this, obj) }
|
||||||
|
|
||||||
object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> {
|
public object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> {
|
||||||
override fun invoke(meta: Meta, context: Context): IOFormat<Double> = this
|
override fun invoke(meta: Meta, context: Context): IOFormat<Double> = this
|
||||||
|
|
||||||
override val name: Name = "double".asName()
|
override val name: Name = "double".asName()
|
||||||
|
|
||||||
override val type: KClass<out Double> get() = Double::class
|
override val type: KClass<out Double> get() = Double::class
|
||||||
|
|
||||||
override fun Output.writeObject(obj: Double) {
|
override fun writeObject(output: Output, obj: kotlin.Double) {
|
||||||
writeDouble(obj)
|
output.writeDouble(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Double = readDouble()
|
override fun readObject(input: Input): Double = input.readDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> {
|
public object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> {
|
||||||
override fun invoke(meta: Meta, context: Context): IOFormat<Value> = this
|
override fun invoke(meta: Meta, context: Context): IOFormat<Value> = this
|
||||||
|
|
||||||
override val name: Name = "value".asName()
|
override val name: Name = "value".asName()
|
||||||
|
|
||||||
override val type: KClass<out Value> get() = Value::class
|
override val type: KClass<out Value> get() = Value::class
|
||||||
|
|
||||||
override fun Output.writeObject(obj: Value) {
|
override fun writeObject(output: Output, obj: Value) {
|
||||||
BinaryMetaFormat.run { writeValue(obj) }
|
BinaryMetaFormat.run { output.writeValue(obj) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Value {
|
override fun readObject(input: Input): Value {
|
||||||
return (BinaryMetaFormat.run { readMetaItem() } as? MetaItem.ValueItem)?.value
|
return (BinaryMetaFormat.run { input.readMetaItem() } as? MetaItem.ValueItem)?.value
|
||||||
?: error("The item is not a value")
|
?: error("The item is not a value")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,14 +11,14 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
val ioFormatFactories by lazy {
|
public val ioFormatFactories: Collection<IOFormatFactory<*>> by lazy {
|
||||||
context.content<IOFormatFactory<*>>(IO_FORMAT_TYPE).values
|
context.gather<IOFormatFactory<*>>(IO_FORMAT_TYPE).values
|
||||||
}
|
}
|
||||||
|
|
||||||
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 key = item.string ?: item.node[NAME_KEY]?.string ?: error("Format name not defined")
|
||||||
val name = key.toName()
|
val name = key.toName()
|
||||||
return ioFormatFactories.find { it.name == name }?.let {
|
return ioFormatFactories.find { it.name == name }?.let {
|
||||||
@ -29,40 +29,40 @@ class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val metaFormatFactories by lazy {
|
public val metaFormatFactories: Collection<MetaFormatFactory> by lazy {
|
||||||
context.content<MetaFormatFactory>(META_FORMAT_TYPE).values
|
context.gather<MetaFormatFactory>(META_FORMAT_TYPE).values
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolveMetaFormat(key: Short, meta: Meta = Meta.EMPTY): MetaFormat? =
|
public fun resolveMetaFormat(key: Short, meta: Meta = Meta.EMPTY): MetaFormat? =
|
||||||
metaFormatFactories.find { it.key == key }?.invoke(meta)
|
metaFormatFactories.find { it.key == key }?.invoke(meta)
|
||||||
|
|
||||||
fun resolveMetaFormat(name: String, meta: Meta = Meta.EMPTY): MetaFormat? =
|
public fun resolveMetaFormat(name: String, meta: Meta = Meta.EMPTY): MetaFormat? =
|
||||||
metaFormatFactories.find { it.shortName == name }?.invoke(meta)
|
metaFormatFactories.find { it.shortName == name }?.invoke(meta)
|
||||||
|
|
||||||
val envelopeFormatFactories by lazy {
|
public val envelopeFormatFactories: Collection<EnvelopeFormatFactory> by lazy {
|
||||||
context.content<EnvelopeFormatFactory>(ENVELOPE_FORMAT_TYPE).values
|
context.gather<EnvelopeFormatFactory>(ENVELOPE_FORMAT_TYPE).values
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolveEnvelopeFormat(name: Name, meta: Meta = Meta.EMPTY): EnvelopeFormat? =
|
private fun resolveEnvelopeFormat(name: Name, meta: Meta = Meta.EMPTY): EnvelopeFormat? =
|
||||||
envelopeFormatFactories.find { it.name == name }?.invoke(meta, context)
|
envelopeFormatFactories.find { it.name == name }?.invoke(meta, context)
|
||||||
|
|
||||||
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 name = item.string ?: item.node[NAME_KEY]?.string ?: error("Envelope format name not defined")
|
||||||
val meta = item.node[META_KEY].node ?: Meta.EMPTY
|
val meta = item.node[META_KEY].node ?: Meta.EMPTY
|
||||||
return resolveEnvelopeFormat(name.toName(), meta)
|
return resolveEnvelopeFormat(name.toName(), meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun provideTop(target: String): Map<Name, Any> {
|
override fun content(target: String): Map<Name, Any> {
|
||||||
return when (target) {
|
return when (target) {
|
||||||
META_FORMAT_TYPE -> defaultMetaFormats.toMap()
|
META_FORMAT_TYPE -> defaultMetaFormats.toMap()
|
||||||
ENVELOPE_FORMAT_TYPE -> defaultEnvelopeFormats.toMap()
|
ENVELOPE_FORMAT_TYPE -> defaultEnvelopeFormats.toMap()
|
||||||
else -> super.provideTop(target)
|
else -> super.content(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : PluginFactory<IOPlugin> {
|
public companion object : PluginFactory<IOPlugin> {
|
||||||
val defaultMetaFormats: List<MetaFormatFactory> = listOf(JsonMetaFormat, BinaryMetaFormat)
|
public val defaultMetaFormats: List<MetaFormatFactory> = listOf(JsonMetaFormat, BinaryMetaFormat)
|
||||||
val defaultEnvelopeFormats = listOf(TaggedEnvelopeFormat, TaglessEnvelopeFormat)
|
public val defaultEnvelopeFormats: List<EnvelopeFormatFactory> = listOf(TaggedEnvelopeFormat, TaglessEnvelopeFormat)
|
||||||
|
|
||||||
override val tag: PluginTag = PluginTag("io", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag("io", group = PluginTag.DATAFORGE_GROUP)
|
||||||
|
|
||||||
@ -71,4 +71,4 @@ class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val Context.io: IOPlugin get() = plugins.fetch(IOPlugin)
|
public val Context.io: IOPlugin get() = plugins.fetch(IOPlugin)
|
@ -12,45 +12,46 @@ import hep.dataforge.meta.toJson
|
|||||||
import hep.dataforge.meta.toMetaItem
|
import hep.dataforge.meta.toMetaItem
|
||||||
import kotlinx.io.Input
|
import kotlinx.io.Input
|
||||||
import kotlinx.io.Output
|
import kotlinx.io.Output
|
||||||
import kotlinx.io.readByteArray
|
import kotlinx.io.text.readUtf8String
|
||||||
import kotlinx.io.text.writeUtf8String
|
import kotlinx.io.text.writeUtf8String
|
||||||
import kotlinx.serialization.UnstableDefault
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonObjectSerializer
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
|
||||||
@OptIn(UnstableDefault::class)
|
/**
|
||||||
class JsonMetaFormat(private val json: Json = DEFAULT_JSON) : MetaFormat {
|
* A Json format for Meta representation
|
||||||
|
*/
|
||||||
|
public class JsonMetaFormat(private val json: Json = DEFAULT_JSON) : MetaFormat {
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
|
||||||
val jsonObject = meta.toJson(descriptor)
|
val jsonObject = meta.toJson(descriptor)
|
||||||
writeUtf8String(json.stringify(JsonObjectSerializer, jsonObject))
|
output.writeUtf8String(json.encodeToString(JsonObject.serializer(), jsonObject))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta{
|
override fun toMeta(): Meta = Meta {
|
||||||
NAME_KEY put name.toString()
|
NAME_KEY put name.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||||
val str = readByteArray().decodeToString()
|
val str = input.readUtf8String()//readByteArray().decodeToString()
|
||||||
val jsonElement = json.parseJson(str)
|
val jsonElement = json.parseToJsonElement(str)
|
||||||
val item = jsonElement.toMetaItem(descriptor)
|
val item = jsonElement.toMetaItem(descriptor)
|
||||||
return item.node ?: Meta.EMPTY
|
return item.node ?: Meta.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : MetaFormatFactory {
|
public companion object : MetaFormatFactory {
|
||||||
val DEFAULT_JSON = Json { prettyPrint = true }
|
public val DEFAULT_JSON: Json = Json { prettyPrint = true }
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): MetaFormat = default
|
override fun invoke(meta: Meta, context: Context): MetaFormat = default
|
||||||
|
|
||||||
override val shortName = "json"
|
override val shortName: String = "json"
|
||||||
override val key: Short = 0x4a53//"JS"
|
override val key: Short = 0x4a53//"JS"
|
||||||
|
|
||||||
private val default = JsonMetaFormat()
|
private val default = JsonMetaFormat()
|
||||||
|
|
||||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) =
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
||||||
default.run { writeMeta(meta, descriptor) }
|
default.run { writeMeta(output, meta, descriptor) }
|
||||||
|
|
||||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta =
|
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta =
|
||||||
default.run { readMeta(descriptor) }
|
default.run { readMeta(input, descriptor) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,46 +17,50 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* A format for meta serialization
|
* A format for meta serialization
|
||||||
*/
|
*/
|
||||||
|
public interface MetaFormat : IOFormat<Meta> {
|
||||||
|
|
||||||
interface MetaFormat : IOFormat<Meta> {
|
override fun writeObject(output: Output, obj: Meta) {
|
||||||
|
writeMeta(output, obj, null)
|
||||||
override fun Output.writeObject(obj: Meta) {
|
|
||||||
writeMeta(obj, null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Meta = readMeta()
|
override fun readObject(input: Input): Meta = readMeta(input)
|
||||||
|
|
||||||
fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor? = null)
|
public fun writeMeta(
|
||||||
fun Input.readMeta(descriptor: NodeDescriptor? = null): Meta
|
output: Output,
|
||||||
|
meta: Meta,
|
||||||
|
descriptor: NodeDescriptor? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun readMeta(input: Input, descriptor: NodeDescriptor? = null): Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
@Type(META_FORMAT_TYPE)
|
@Type(META_FORMAT_TYPE)
|
||||||
interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
|
public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
|
||||||
val shortName: String
|
public val shortName: String
|
||||||
|
|
||||||
override val name: Name get() = "meta".asName() + shortName
|
override val name: Name get() = "meta".asName() + shortName
|
||||||
|
|
||||||
override val type: KClass<out Meta> get() = Meta::class
|
override val type: KClass<out Meta> get() = Meta::class
|
||||||
|
|
||||||
val key: Short get() = name.hashCode().toShort()
|
public val key: Short get() = name.hashCode().toShort()
|
||||||
|
|
||||||
override operator fun invoke(meta: Meta, context: Context): MetaFormat
|
override operator fun invoke(meta: Meta, context: Context): MetaFormat
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val META_FORMAT_TYPE = "io.format.meta"
|
public const val META_FORMAT_TYPE: String = "io.format.meta"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.toString(format: MetaFormat): String = buildByteArray {
|
public fun Meta.toString(format: MetaFormat): String = buildByteArray {
|
||||||
format.run { writeObject(this@toString) }
|
format.run { writeObject(this@buildByteArray, this@toString) }
|
||||||
}.decodeToString()
|
}.decodeToString()
|
||||||
|
|
||||||
fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory())
|
public fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory())
|
||||||
|
|
||||||
fun MetaFormat.parse(str: String): Meta {
|
public fun MetaFormat.parse(str: String): Meta {
|
||||||
return ByteArrayInput(str.encodeToByteArray()).use { it.readObject() }
|
return ByteArrayInput(str.encodeToByteArray()).use { readObject(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MetaFormatFactory.parse(str: String, formatMeta: Meta): Meta = invoke(formatMeta).parse(str)
|
public fun MetaFormatFactory.parse(str: String, formatMeta: Meta): Meta = invoke(formatMeta).parse(str)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package hep.dataforge.io
|
package hep.dataforge.io
|
||||||
|
|
||||||
interface Responder {
|
/**
|
||||||
|
* An object that could respond to external messages asynchronously
|
||||||
|
*/
|
||||||
|
public interface Responder {
|
||||||
/**
|
/**
|
||||||
* Send a request and wait for response for this specific request
|
* Send a request and wait for response for this specific request
|
||||||
*/
|
*/
|
||||||
suspend fun respond(request: Envelope): Envelope
|
public suspend fun respond(request: Envelope): Envelope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,13 @@ import hep.dataforge.names.plus
|
|||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
|
|
||||||
class TaggedEnvelopeFormat(
|
/**
|
||||||
val io: IOPlugin,
|
* A streaming-friendly envelope format with a short binary tag.
|
||||||
val version: VERSION = VERSION.DF02
|
* TODO add description
|
||||||
|
*/
|
||||||
|
public class TaggedEnvelopeFormat(
|
||||||
|
public val io: IOPlugin,
|
||||||
|
public val version: VERSION = VERSION.DF02,
|
||||||
) : EnvelopeFormat {
|
) : EnvelopeFormat {
|
||||||
|
|
||||||
// private val metaFormat = io.metaFormat(metaFormatKey)
|
// private val metaFormat = io.metaFormat(metaFormatKey)
|
||||||
@ -37,18 +41,23 @@ class TaggedEnvelopeFormat(
|
|||||||
writeRawString(END_SEQUENCE)
|
writeRawString(END_SEQUENCE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
override fun writeEnvelope(
|
||||||
val metaFormat = metaFormatFactory.invoke(formatMeta, io.context)
|
output: Output,
|
||||||
|
envelope: Envelope,
|
||||||
|
metaFormatFactory: MetaFormatFactory,
|
||||||
|
formatMeta: Meta,
|
||||||
|
) {
|
||||||
|
val metaFormat = metaFormatFactory.invoke(formatMeta, this@TaggedEnvelopeFormat.io.context)
|
||||||
val metaBytes = metaFormat.toBinary(envelope.meta)
|
val metaBytes = metaFormat.toBinary(envelope.meta)
|
||||||
val actualSize: ULong = (envelope.data?.size ?: 0).toULong()
|
val actualSize: ULong = (envelope.data?.size ?: 0).toULong()
|
||||||
val tag = Tag(metaFormatFactory.key, metaBytes.size.toUInt() + 2u, actualSize)
|
val tag = Tag(metaFormatFactory.key, metaBytes.size.toUInt() + 2u, actualSize)
|
||||||
writeBinary(tag.toBinary())
|
output.writeBinary(tag.toBinary())
|
||||||
writeBinary(metaBytes)
|
output.writeBinary(metaBytes)
|
||||||
writeRawString("\r\n")
|
output.writeRawString("\r\n")
|
||||||
envelope.data?.let {
|
envelope.data?.let {
|
||||||
writeBinary(it)
|
output.writeBinary(it)
|
||||||
}
|
}
|
||||||
flush()
|
output.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,34 +66,27 @@ class TaggedEnvelopeFormat(
|
|||||||
* @param input an input to read from
|
* @param input an input to read from
|
||||||
* @param formats a collection of meta formats to resolve
|
* @param formats a collection of meta formats to resolve
|
||||||
*/
|
*/
|
||||||
override fun Input.readObject(): Envelope {
|
override fun readObject(input: Input): Envelope {
|
||||||
val tag = readTag(version)
|
val tag = input.readTag(this.version)
|
||||||
|
|
||||||
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
||||||
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
||||||
|
|
||||||
val meta: Meta = limit(tag.metaSize.toInt()).run {
|
val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt()))
|
||||||
metaFormat.run {
|
|
||||||
readObject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val data = readBinary(tag.dataSize.toInt())
|
val data = input.readBinary(tag.dataSize.toInt())
|
||||||
|
|
||||||
return SimpleEnvelope(meta, data)
|
return SimpleEnvelope(meta, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope {
|
override fun readPartial(input: Input): PartialEnvelope {
|
||||||
val tag = readTag(version)
|
val tag = input.readTag(this.version)
|
||||||
|
|
||||||
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
||||||
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
||||||
|
|
||||||
val meta: Meta = limit(tag.metaSize.toInt()).run {
|
val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt()))
|
||||||
metaFormat.run {
|
|
||||||
readObject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PartialEnvelope(meta, version.tagSize + tag.metaSize, tag.dataSize)
|
return PartialEnvelope(meta, version.tagSize + tag.metaSize, tag.dataSize)
|
||||||
}
|
}
|
||||||
@ -92,10 +94,10 @@ class TaggedEnvelopeFormat(
|
|||||||
private data class Tag(
|
private data class Tag(
|
||||||
val metaFormatKey: Short,
|
val metaFormatKey: Short,
|
||||||
val metaSize: UInt,
|
val metaSize: UInt,
|
||||||
val dataSize: ULong
|
val dataSize: ULong,
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class VERSION(val tagSize: UInt) {
|
public enum class VERSION(public val tagSize: UInt) {
|
||||||
DF02(20u),
|
DF02(20u),
|
||||||
DF03(24u)
|
DF03(24u)
|
||||||
}
|
}
|
||||||
@ -107,7 +109,7 @@ class TaggedEnvelopeFormat(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : EnvelopeFormatFactory {
|
public companion object : EnvelopeFormatFactory {
|
||||||
private const val START_SEQUENCE = "#~"
|
private const val START_SEQUENCE = "#~"
|
||||||
private const val END_SEQUENCE = "~#\r\n"
|
private const val END_SEQUENCE = "~#\r\n"
|
||||||
|
|
||||||
@ -158,16 +160,24 @@ class TaggedEnvelopeFormat(
|
|||||||
|
|
||||||
private val default by lazy { invoke() }
|
private val default by lazy { invoke() }
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope =
|
override fun readPartial(input: Input): PartialEnvelope =
|
||||||
default.run { readPartial() }
|
default.run { readPartial(input) }
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) =
|
|
||||||
default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) }
|
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope =
|
|
||||||
default.run { readObject() }
|
|
||||||
|
|
||||||
|
override fun writeEnvelope(
|
||||||
|
output: Output,
|
||||||
|
envelope: Envelope,
|
||||||
|
metaFormatFactory: MetaFormatFactory,
|
||||||
|
formatMeta: Meta,
|
||||||
|
): Unit = default.run {
|
||||||
|
writeEnvelope(
|
||||||
|
output,
|
||||||
|
envelope,
|
||||||
|
metaFormatFactory,
|
||||||
|
formatMeta
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readObject(input: Input): Envelope = default.readObject(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,15 +7,20 @@ import hep.dataforge.meta.Meta
|
|||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.isEmpty
|
import hep.dataforge.meta.isEmpty
|
||||||
import hep.dataforge.meta.string
|
import hep.dataforge.meta.string
|
||||||
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
import kotlinx.io.text.readUtf8Line
|
import kotlinx.io.text.readUtf8Line
|
||||||
import kotlinx.io.text.writeUtf8String
|
import kotlinx.io.text.writeUtf8String
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
class TaglessEnvelopeFormat(
|
/**
|
||||||
val io: IOPlugin,
|
* A text envelope format with human-readable tag.
|
||||||
val meta: Meta = Meta.EMPTY
|
* TODO add description
|
||||||
|
*/
|
||||||
|
public class TaglessEnvelopeFormat(
|
||||||
|
public val io: IOPlugin,
|
||||||
|
public val meta: Meta = Meta.EMPTY,
|
||||||
) : EnvelopeFormat {
|
) : EnvelopeFormat {
|
||||||
|
|
||||||
private val metaStart = meta[META_START_PROPERTY].string ?: DEFAULT_META_START
|
private val metaStart = meta[META_START_PROPERTY].string ?: DEFAULT_META_START
|
||||||
@ -25,39 +30,46 @@ class TaglessEnvelopeFormat(
|
|||||||
writeUtf8String("#? $key: $value;\r\n")
|
writeUtf8String("#? $key: $value;\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
override fun writeEnvelope(
|
||||||
val metaFormat = metaFormatFactory(formatMeta, io.context)
|
output: Output,
|
||||||
|
envelope: Envelope,
|
||||||
|
metaFormatFactory: MetaFormatFactory,
|
||||||
|
formatMeta: Meta
|
||||||
|
) {
|
||||||
|
val metaFormat = metaFormatFactory(formatMeta, this.io.context)
|
||||||
|
|
||||||
//printing header
|
//printing header
|
||||||
writeRawString(TAGLESS_ENVELOPE_HEADER + "\r\n")
|
output.writeRawString(TAGLESS_ENVELOPE_HEADER + "\r\n")
|
||||||
|
|
||||||
//printing all properties
|
//printing all properties
|
||||||
writeProperty(META_TYPE_PROPERTY, metaFormatFactory.shortName)
|
output.writeProperty(META_TYPE_PROPERTY,
|
||||||
|
metaFormatFactory.shortName)
|
||||||
//TODO add optional metaFormat properties
|
//TODO add optional metaFormat properties
|
||||||
val actualSize: Int = envelope.data?.size ?: 0
|
val actualSize: Int = envelope.data?.size ?: 0
|
||||||
|
|
||||||
writeProperty(DATA_LENGTH_PROPERTY, actualSize)
|
output.writeProperty(DATA_LENGTH_PROPERTY, actualSize)
|
||||||
|
|
||||||
//Printing meta
|
//Printing meta
|
||||||
if (!envelope.meta.isEmpty()) {
|
if (!envelope.meta.isEmpty()) {
|
||||||
val metaBytes = metaFormat.toBinary(envelope.meta)
|
val metaBytes = metaFormat.toBinary(envelope.meta)
|
||||||
writeProperty(META_LENGTH_PROPERTY, metaBytes.size + 2)
|
output.writeProperty(META_LENGTH_PROPERTY,
|
||||||
writeUtf8String(metaStart + "\r\n")
|
metaBytes.size + 2)
|
||||||
writeBinary(metaBytes)
|
output.writeUtf8String(this.metaStart + "\r\n")
|
||||||
writeRawString("\r\n")
|
output.writeBinary(metaBytes)
|
||||||
|
output.writeRawString("\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
//Printing data
|
//Printing data
|
||||||
envelope.data?.let { data ->
|
envelope.data?.let { data ->
|
||||||
writeUtf8String(dataStart + "\r\n")
|
output.writeUtf8String(this.dataStart + "\r\n")
|
||||||
writeBinary(data)
|
output.writeBinary(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope {
|
override fun readObject(input: Input): Envelope {
|
||||||
var line: String
|
var line: String
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line() // ?: error("Input does not contain tagless envelope header")
|
line = input.readUtf8Line() // ?: error("Input does not contain tagless envelope header")
|
||||||
} while (!line.startsWith(TAGLESS_ENVELOPE_HEADER))
|
} while (!line.startsWith(TAGLESS_ENVELOPE_HEADER))
|
||||||
val properties = HashMap<String, String>()
|
val properties = HashMap<String, String>()
|
||||||
|
|
||||||
@ -70,8 +82,8 @@ class TaglessEnvelopeFormat(
|
|||||||
properties[key] = value
|
properties[key] = value
|
||||||
}
|
}
|
||||||
//If can't read line, return envelope without data
|
//If can't read line, return envelope without data
|
||||||
if (exhausted()) return SimpleEnvelope(Meta.EMPTY, null)
|
if (input.exhausted()) return SimpleEnvelope(Meta.EMPTY, null)
|
||||||
line = readUtf8Line()
|
line = input.readUtf8Line()
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta: Meta = Meta.EMPTY
|
var meta: Meta = Meta.EMPTY
|
||||||
@ -80,19 +92,15 @@ class TaglessEnvelopeFormat(
|
|||||||
val metaFormat = properties[META_TYPE_PROPERTY]?.let { io.resolveMetaFormat(it) } ?: JsonMetaFormat
|
val metaFormat = properties[META_TYPE_PROPERTY]?.let { io.resolveMetaFormat(it) } ?: JsonMetaFormat
|
||||||
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
||||||
meta = if (metaSize != null) {
|
meta = if (metaSize != null) {
|
||||||
limit(metaSize).run {
|
metaFormat.readObject(input.limit(metaSize))
|
||||||
metaFormat.run { readObject() }
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
metaFormat.run {
|
metaFormat.readObject(input)
|
||||||
readObject()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
line = readUtf8Line()
|
line = input.readUtf8Line()
|
||||||
} catch (ex: EOFException) {
|
} catch (ex: EOFException) {
|
||||||
//returning an Envelope without data if end of input is reached
|
//returning an Envelope without data if end of input is reached
|
||||||
return SimpleEnvelope(meta, null)
|
return SimpleEnvelope(meta, null)
|
||||||
@ -100,24 +108,24 @@ class TaglessEnvelopeFormat(
|
|||||||
} while (!line.startsWith(dataStart))
|
} while (!line.startsWith(dataStart))
|
||||||
|
|
||||||
val data: Binary? = if (properties.containsKey(DATA_LENGTH_PROPERTY)) {
|
val data: Binary? = if (properties.containsKey(DATA_LENGTH_PROPERTY)) {
|
||||||
readBinary(properties[DATA_LENGTH_PROPERTY]!!.toInt())
|
input.readBinary(properties[DATA_LENGTH_PROPERTY]!!.toInt())
|
||||||
// val bytes = ByteArray(properties[DATA_LENGTH_PROPERTY]!!.toInt())
|
// val bytes = ByteArray(properties[DATA_LENGTH_PROPERTY]!!.toInt())
|
||||||
// readByteArray(bytes)
|
// readByteArray(bytes)
|
||||||
// bytes.asBinary()
|
// bytes.asBinary()
|
||||||
} else {
|
} else {
|
||||||
Binary {
|
Binary {
|
||||||
copyTo(this)
|
input.copyTo(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SimpleEnvelope(meta, data)
|
return SimpleEnvelope(meta, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope {
|
override fun readPartial(input: Input): PartialEnvelope {
|
||||||
var offset = 0u
|
var offset = 0u
|
||||||
var line: String
|
var line: String
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line()// ?: error("Input does not contain tagless envelope header")
|
line = input.readUtf8Line()// ?: error("Input does not contain tagless envelope header")
|
||||||
offset += line.encodeToByteArray().size.toUInt()
|
offset += line.encodeToByteArray().size.toUInt()
|
||||||
} while (!line.startsWith(TAGLESS_ENVELOPE_HEADER))
|
} while (!line.startsWith(TAGLESS_ENVELOPE_HEADER))
|
||||||
val properties = HashMap<String, String>()
|
val properties = HashMap<String, String>()
|
||||||
@ -131,7 +139,7 @@ class TaglessEnvelopeFormat(
|
|||||||
properties[key] = value
|
properties[key] = value
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
line = readUtf8Line()
|
line = input.readUtf8Line()
|
||||||
offset += line.encodeToByteArray().size.toUInt()
|
offset += line.encodeToByteArray().size.toUInt()
|
||||||
} catch (ex: EOFException) {
|
} catch (ex: EOFException) {
|
||||||
return PartialEnvelope(Meta.EMPTY, offset.toUInt(), 0.toULong())
|
return PartialEnvelope(Meta.EMPTY, offset.toUInt(), 0.toULong())
|
||||||
@ -145,16 +153,14 @@ class TaglessEnvelopeFormat(
|
|||||||
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
||||||
meta = if (metaSize != null) {
|
meta = if (metaSize != null) {
|
||||||
offset += metaSize.toUInt()
|
offset += metaSize.toUInt()
|
||||||
limit(metaSize).run {
|
metaFormat.readObject(input.limit(metaSize))
|
||||||
metaFormat.run { readObject() }
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error("Can't partially read an envelope with undefined meta size")
|
error("Can't partially read an envelope with undefined meta size")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
line = readUtf8Line() //?: return PartialEnvelope(Meta.EMPTY, offset.toUInt(), 0.toULong())
|
line = input.readUtf8Line() //?: return PartialEnvelope(Meta.EMPTY, offset.toUInt(), 0.toULong())
|
||||||
offset += line.encodeToByteArray().size.toUInt()
|
offset += line.encodeToByteArray().size.toUInt()
|
||||||
//returning an Envelope without data if end of input is reached
|
//returning an Envelope without data if end of input is reached
|
||||||
} while (!line.startsWith(dataStart))
|
} while (!line.startsWith(dataStart))
|
||||||
@ -168,26 +174,26 @@ class TaglessEnvelopeFormat(
|
|||||||
META_KEY put meta
|
META_KEY put meta
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : EnvelopeFormatFactory {
|
public companion object : EnvelopeFormatFactory {
|
||||||
|
|
||||||
private val propertyPattern = "#\\?\\s*(?<key>[\\w.]*)\\s*:\\s*(?<value>[^;]*);?".toRegex()
|
private val propertyPattern = "#\\?\\s*([\\w.]*)\\s*:\\s*([^;]*);?".toRegex()
|
||||||
|
|
||||||
const val META_TYPE_PROPERTY = "metaType"
|
public const val META_TYPE_PROPERTY: String = "metaType"
|
||||||
const val META_LENGTH_PROPERTY = "metaLength"
|
public const val META_LENGTH_PROPERTY: String = "metaLength"
|
||||||
const val DATA_LENGTH_PROPERTY = "dataLength"
|
public const val DATA_LENGTH_PROPERTY: String = "dataLength"
|
||||||
|
|
||||||
|
|
||||||
const val TAGLESS_ENVELOPE_TYPE = "tagless"
|
public const val TAGLESS_ENVELOPE_TYPE: String = "tagless"
|
||||||
|
|
||||||
const val TAGLESS_ENVELOPE_HEADER = "#~DFTL~#"
|
public const val TAGLESS_ENVELOPE_HEADER: String = "#~DFTL~#"
|
||||||
const val META_START_PROPERTY = "metaSeparator"
|
public const val META_START_PROPERTY: String = "metaSeparator"
|
||||||
const val DEFAULT_META_START = "#~META~#"
|
public const val DEFAULT_META_START: String = "#~META~#"
|
||||||
const val DATA_START_PROPERTY = "dataSeparator"
|
public const val DATA_START_PROPERTY: String = "dataSeparator"
|
||||||
const val DEFAULT_DATA_START = "#~DATA~#"
|
public const val DEFAULT_DATA_START: String = "#~DATA~#"
|
||||||
|
|
||||||
const val code: Int = 0x4446544c //DFTL
|
public const val code: Int = 0x4446544c //DFTL
|
||||||
|
|
||||||
override val name = TAGLESS_ENVELOPE_TYPE.asName()
|
override val name: Name = TAGLESS_ENVELOPE_TYPE.asName()
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): EnvelopeFormat {
|
override fun invoke(meta: Meta, context: Context): EnvelopeFormat {
|
||||||
return TaglessEnvelopeFormat(context.io, meta)
|
return TaglessEnvelopeFormat(context.io, meta)
|
||||||
@ -195,14 +201,24 @@ class TaglessEnvelopeFormat(
|
|||||||
|
|
||||||
private val default by lazy { invoke() }
|
private val default by lazy { invoke() }
|
||||||
|
|
||||||
override fun Input.readPartial(): PartialEnvelope =
|
override fun readPartial(input: Input): PartialEnvelope =
|
||||||
default.run { readPartial() }
|
default.run { readPartial(input) }
|
||||||
|
|
||||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) =
|
override fun writeEnvelope(
|
||||||
default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) }
|
output: Output,
|
||||||
|
envelope: Envelope,
|
||||||
|
metaFormatFactory: MetaFormatFactory,
|
||||||
|
formatMeta: Meta,
|
||||||
|
): Unit = default.run {
|
||||||
|
writeEnvelope(
|
||||||
|
output,
|
||||||
|
envelope,
|
||||||
|
metaFormatFactory,
|
||||||
|
formatMeta
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun Input.readObject(): Envelope =
|
override fun readObject(input: Input): Envelope = default.readObject(input)
|
||||||
default.run { readObject() }
|
|
||||||
|
|
||||||
override fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat? {
|
override fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat? {
|
||||||
return try {
|
return try {
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
package hep.dataforge.io.functions
|
|
||||||
|
|
||||||
import hep.dataforge.context.ContextAware
|
|
||||||
import hep.dataforge.io.IOFormat
|
|
||||||
import hep.dataforge.io.IOPlugin
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.get
|
|
||||||
import hep.dataforge.names.asName
|
|
||||||
import hep.dataforge.names.plus
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A server that could produce asynchronous function values
|
|
||||||
*/
|
|
||||||
interface FunctionServer : ContextAware {
|
|
||||||
/**
|
|
||||||
* Call a function with given name and descriptor
|
|
||||||
*/
|
|
||||||
suspend fun <T : Any, R : Any> call(meta: Meta, arg: T, inputType: KClass<out T>, outputType: KClass<out R>): R
|
|
||||||
|
|
||||||
suspend fun <T : Any, R : Any> callMany(
|
|
||||||
meta: Meta,
|
|
||||||
arg: List<T>,
|
|
||||||
inputType: KClass<out T>,
|
|
||||||
outputType: KClass<out R>
|
|
||||||
): List<R> = List(arg.size) {
|
|
||||||
call<T, R>(meta, arg[it], inputType, outputType)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a generic suspended function with given name and descriptor
|
|
||||||
*/
|
|
||||||
fun <T : Any, R : Any> function(
|
|
||||||
meta: Meta,
|
|
||||||
inputType: KClass<out T>,
|
|
||||||
outputType: KClass<out R>
|
|
||||||
): (suspend (T) -> R) = { call(meta, it, inputType, outputType) }
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val FUNCTION_NAME_KEY = "function"
|
|
||||||
val FORMAT_KEY = "format".asName()
|
|
||||||
val INPUT_FORMAT_KEY = FORMAT_KEY + "input"
|
|
||||||
val OUTPUT_FORMAT_KEY = FORMAT_KEY + "output"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend inline fun <reified T : Any, reified R : Any> FunctionServer.call(meta: Meta, arg: T) =
|
|
||||||
call(meta, arg, T::class, R::class)
|
|
||||||
|
|
||||||
suspend inline fun <reified T : Any, reified R : Any> FunctionServer.callMany(meta: Meta, arg: List<T>) =
|
|
||||||
callMany(meta, arg, T::class, R::class)
|
|
||||||
|
|
||||||
inline fun <reified T : Any, reified R : Any> FunctionServer.function(meta: Meta) =
|
|
||||||
function(meta, T::class, R::class)
|
|
||||||
|
|
||||||
fun <T : Any> IOPlugin.getInputFormat(meta: Meta, type: KClass<out T>): IOFormat<T> {
|
|
||||||
return meta[FunctionServer.INPUT_FORMAT_KEY]?.let {
|
|
||||||
resolveIOFormat<T>(it, type)
|
|
||||||
} ?: error("Input format not resolved")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R : Any> IOPlugin.getOutputFormat(meta: Meta, type: KClass<out R>): IOFormat<R> {
|
|
||||||
return meta[FunctionServer.OUTPUT_FORMAT_KEY]?.let {
|
|
||||||
resolveIOFormat<R>(it, type)
|
|
||||||
} ?: error("Input format not resolved")
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> IOPlugin.getInputFormat(meta: Meta): IOFormat<T> =
|
|
||||||
getInputFormat(meta, T::class)
|
|
||||||
|
|
||||||
inline fun <reified R : Any> IOPlugin.getOutputFormat(meta: Meta): IOFormat<R> =
|
|
||||||
getOutputFormat(meta, R::class)
|
|
||||||
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
|||||||
package hep.dataforge.io.functions
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.context.ContextAware
|
|
||||||
import hep.dataforge.io.*
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.get
|
|
||||||
import hep.dataforge.meta.int
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
class RemoteFunctionClient(override val context: Context, val responder: Responder) : FunctionServer, ContextAware {
|
|
||||||
|
|
||||||
private fun <T : Any> IOPlugin.encodeOne(
|
|
||||||
meta: Meta,
|
|
||||||
value: T,
|
|
||||||
valueType: KClass<out T> = value::class
|
|
||||||
): Envelope = Envelope.invoke {
|
|
||||||
meta(meta)
|
|
||||||
type = REQUEST_TYPE
|
|
||||||
data {
|
|
||||||
val inputFormat: IOFormat<T> = getInputFormat(meta, valueType)
|
|
||||||
inputFormat.run {
|
|
||||||
writeObject(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : Any> IOPlugin.encodeMany(
|
|
||||||
meta: Meta,
|
|
||||||
values: List<T>,
|
|
||||||
valueType: KClass<out T>
|
|
||||||
): Envelope = Envelope.invoke {
|
|
||||||
meta(meta)
|
|
||||||
type = REQUEST_TYPE
|
|
||||||
meta {
|
|
||||||
SIZE_KEY put values.size
|
|
||||||
}
|
|
||||||
data {
|
|
||||||
val inputFormat: IOFormat<T> = getInputFormat(meta, valueType)
|
|
||||||
inputFormat.run {
|
|
||||||
values.forEach {
|
|
||||||
writeObject(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <R : Any> IOPlugin.decode(envelope: Envelope, valueType: KClass<out R>): List<R> {
|
|
||||||
require(envelope.type == RESPONSE_TYPE) { "Unexpected message type: ${envelope.type}" }
|
|
||||||
val size = envelope.meta[SIZE_KEY].int ?: 1
|
|
||||||
|
|
||||||
return if (size == 0) {
|
|
||||||
emptyList()
|
|
||||||
} else {
|
|
||||||
val outputFormat: IOFormat<R> = getOutputFormat(envelope.meta, valueType)
|
|
||||||
envelope.data?.read {
|
|
||||||
List<R>(size) {
|
|
||||||
outputFormat.run {
|
|
||||||
readObject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: error("Message does not contain data")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val plugin by lazy {
|
|
||||||
context.plugins.load(IOPlugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun <T : Any, R : Any> call(
|
|
||||||
meta: Meta,
|
|
||||||
arg: T,
|
|
||||||
inputType: KClass<out T>,
|
|
||||||
outputType: KClass<out R>
|
|
||||||
): R = plugin.run {
|
|
||||||
val request = encodeOne(meta, arg)
|
|
||||||
val response = responder.respond(request)
|
|
||||||
return decode<R>(response, outputType).first()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun <T : Any, R : Any> callMany(
|
|
||||||
meta: Meta,
|
|
||||||
arg: List<T>,
|
|
||||||
inputType: KClass<out T>,
|
|
||||||
outputType: KClass<out R>
|
|
||||||
): List<R> = plugin.run {
|
|
||||||
val request = encodeMany(meta, arg, inputType)
|
|
||||||
val response = responder.respond(request)
|
|
||||||
return decode<R>(response, outputType)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val REQUEST_TYPE = "function.request"
|
|
||||||
const val RESPONSE_TYPE = "function.response"
|
|
||||||
|
|
||||||
const val SIZE_KEY = "size"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package hep.dataforge.io.functions
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.context.ContextAware
|
|
||||||
import hep.dataforge.io.Envelope
|
|
||||||
import hep.dataforge.io.IOPlugin
|
|
||||||
import hep.dataforge.io.Responder
|
|
||||||
import hep.dataforge.io.type
|
|
||||||
import hep.dataforge.meta.get
|
|
||||||
import hep.dataforge.meta.int
|
|
||||||
|
|
||||||
class RemoteFunctionServer(
|
|
||||||
override val context: Context,
|
|
||||||
val functionServer: FunctionServer
|
|
||||||
) : ContextAware, Responder {
|
|
||||||
|
|
||||||
private val plugin by lazy {
|
|
||||||
context.plugins.load(IOPlugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun respond(request: Envelope): Envelope {
|
|
||||||
require(request.type == RemoteFunctionClient.REQUEST_TYPE) { "Unexpected message type: ${request.type}" }
|
|
||||||
|
|
||||||
val inputFormat = plugin.getInputFormat<Any>(request.meta)
|
|
||||||
val outputFormat = plugin.getOutputFormat<Any>(request.meta)
|
|
||||||
|
|
||||||
val size = request.meta[RemoteFunctionClient.SIZE_KEY].int ?: 1
|
|
||||||
|
|
||||||
val input = request.data?.read {
|
|
||||||
inputFormat.run {
|
|
||||||
List(size) {
|
|
||||||
readObject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: error("Input is empty")
|
|
||||||
|
|
||||||
val output = functionServer.callMany<Any, Any>(
|
|
||||||
request.meta,
|
|
||||||
input
|
|
||||||
)
|
|
||||||
|
|
||||||
return Envelope.invoke {
|
|
||||||
meta {
|
|
||||||
meta(request.meta)
|
|
||||||
}
|
|
||||||
type = RemoteFunctionClient.RESPONSE_TYPE
|
|
||||||
data {
|
|
||||||
outputFormat.run {
|
|
||||||
output.forEach {
|
|
||||||
writeObject(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,26 +3,26 @@ package hep.dataforge.io
|
|||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
fun Output.writeRawString(str: String) {
|
public fun Output.writeRawString(str: String) {
|
||||||
str.forEach { writeByte(it.toByte()) }
|
str.forEach { writeByte(it.toByte()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Input.readRawString(size: Int): String {
|
public fun Input.readRawString(size: Int): String {
|
||||||
val array = CharArray(size) { readByte().toChar() }
|
val array = CharArray(size) { readByte().toChar() }
|
||||||
return String(array)
|
return array.concatToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun buildByteArray(expectedSize: Int = 16, block: Output.() -> Unit): ByteArray =
|
public inline fun buildByteArray(expectedSize: Int = 16, block: Output.() -> Unit): ByteArray =
|
||||||
ByteArrayOutput(expectedSize).apply(block).toByteArray()
|
ByteArrayOutput(expectedSize).apply(block).toByteArray()
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
inline fun Binary(expectedSize: Int = 16, block: Output.() -> Unit): Binary =
|
public inline fun Binary(expectedSize: Int = 16, block: Output.() -> Unit): Binary =
|
||||||
buildByteArray(expectedSize, block).asBinary()
|
buildByteArray(expectedSize, block).asBinary()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View section of a [Binary] as an independent binary
|
* View section of a [Binary] as an independent binary
|
||||||
*/
|
*/
|
||||||
class BinaryView(private val source: Binary, private val start: Int, override val size: Int) : Binary {
|
public class BinaryView(private val source: Binary, private val start: Int, override val size: Int) : Binary {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(start > 0)
|
require(start > 0)
|
||||||
@ -34,6 +34,6 @@ class BinaryView(private val source: Binary, private val start: Int, override va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Binary.view(start: Int, size: Int) = BinaryView(this, start, size)
|
public fun Binary.view(start: Int, size: Int): BinaryView = BinaryView(this, start, size)
|
||||||
|
|
||||||
operator fun Binary.get(range: IntRange) = view(range.first, range.last - range.first)
|
public operator fun Binary.get(range: IntRange): BinaryView = view(range.first, range.last - range.first)
|
@ -23,9 +23,9 @@ class EnvelopeFormatTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testTaggedFormat(){
|
fun testTaggedFormat(){
|
||||||
TaggedEnvelopeFormat.run {
|
TaggedEnvelopeFormat.run {
|
||||||
val byteArray = this.toByteArray(envelope)
|
val byteArray = writeToByteArray(envelope)
|
||||||
//println(byteArray.decodeToString())
|
//println(byteArray.decodeToString())
|
||||||
val res = readByteArray(byteArray)
|
val res = readFromByteArray(byteArray)
|
||||||
assertEquals(envelope.meta,res.meta)
|
assertEquals(envelope.meta,res.meta)
|
||||||
val double = res.data?.read {
|
val double = res.data?.read {
|
||||||
readDouble()
|
readDouble()
|
||||||
@ -37,9 +37,9 @@ class EnvelopeFormatTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testTaglessFormat(){
|
fun testTaglessFormat(){
|
||||||
TaglessEnvelopeFormat.run {
|
TaglessEnvelopeFormat.run {
|
||||||
val byteArray = toByteArray(envelope)
|
val byteArray = writeToByteArray(envelope)
|
||||||
//println(byteArray.decodeToString())
|
//println(byteArray.decodeToString())
|
||||||
val res = readByteArray(byteArray)
|
val res = readFromByteArray(byteArray)
|
||||||
assertEquals(envelope.meta,res.meta)
|
assertEquals(envelope.meta,res.meta)
|
||||||
val double = res.data?.read {
|
val double = res.data?.read {
|
||||||
readDouble()
|
readDouble()
|
||||||
|
@ -3,18 +3,16 @@ package hep.dataforge.io
|
|||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
||||||
import kotlinx.io.asBinary
|
import kotlinx.io.asBinary
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.*
|
||||||
import kotlinx.serialization.json.json
|
|
||||||
import kotlinx.serialization.json.jsonArray
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
fun Meta.toByteArray(format: MetaFormat = JsonMetaFormat) = buildByteArray {
|
fun Meta.toByteArray(format: MetaFormat = JsonMetaFormat) = buildByteArray {
|
||||||
format.run { writeObject(this@toByteArray) }
|
format.writeObject(this@buildByteArray, this@toByteArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MetaFormat.fromByteArray(packet: ByteArray): Meta {
|
fun MetaFormat.fromByteArray(packet: ByteArray): Meta {
|
||||||
return packet.asBinary().read { readObject() }
|
return packet.asBinary().read { readObject(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class MetaFormatTest {
|
class MetaFormatTest {
|
||||||
@ -57,21 +55,21 @@ class MetaFormatTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testJsonToMeta() {
|
fun testJsonToMeta() {
|
||||||
val json = jsonArray {
|
val json = buildJsonArray {
|
||||||
//top level array
|
//top level array
|
||||||
+jsonArray {
|
add(buildJsonArray {
|
||||||
+JsonPrimitive(88)
|
add(JsonPrimitive(88))
|
||||||
+json {
|
add(buildJsonObject {
|
||||||
"c" to "aasdad"
|
put("c", "aasdad")
|
||||||
"d" to true
|
put("d", true)
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
+"value"
|
add("value")
|
||||||
+jsonArray {
|
add(buildJsonArray {
|
||||||
+JsonPrimitive(1.0)
|
add(JsonPrimitive(1.0))
|
||||||
+JsonPrimitive(2.0)
|
add(JsonPrimitive(2.0))
|
||||||
+JsonPrimitive(3.0)
|
add(JsonPrimitive(3.0))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
val meta = json.toMetaItem().node!!
|
val meta = json.toMetaItem().node!!
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
package hep.dataforge.io
|
package hep.dataforge.io
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.MetaSerializer
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.cbor.Cbor
|
import kotlinx.serialization.cbor.Cbor
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
val JSON_PRETTY: Json = Json { prettyPrint = true; useArrayPolymorphism = true }
|
||||||
|
val JSON_PLAIN: Json = Json { prettyPrint = false; useArrayPolymorphism = true }
|
||||||
|
|
||||||
class MetaSerializerTest {
|
class MetaSerializerTest {
|
||||||
val meta = Meta {
|
val meta = Meta {
|
||||||
"a" put 22
|
"a" put 22
|
||||||
@ -19,29 +26,33 @@ class MetaSerializerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMetaSerialization() {
|
fun testMetaSerialization() {
|
||||||
val string = JSON_PRETTY.stringify(MetaSerializer, meta)
|
val string = JSON_PRETTY.encodeToString(MetaSerializer, meta)
|
||||||
val restored = JSON_PLAIN.parse(MetaSerializer, string)
|
println(string)
|
||||||
assertEquals(restored, meta)
|
val restored = JSON_PLAIN.decodeFromString(MetaSerializer, string)
|
||||||
|
assertEquals(meta, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
@Test
|
@Test
|
||||||
fun testCborSerialization() {
|
fun testCborSerialization() {
|
||||||
val bytes = Cbor.dump(MetaSerializer, meta)
|
val bytes = Cbor.encodeToByteArray(MetaSerializer, meta)
|
||||||
println(bytes.contentToString())
|
println(bytes.decodeToString())
|
||||||
val restored = Cbor.load(MetaSerializer, bytes)
|
val restored = Cbor.decodeFromByteArray(MetaSerializer, bytes)
|
||||||
assertEquals(restored, meta)
|
assertEquals(meta, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNameSerialization() {
|
fun testNameSerialization() {
|
||||||
val name = "a.b.c".toName()
|
val name = "a.b.c".toName()
|
||||||
val string = JSON_PRETTY.stringify(Name.serializer(), name)
|
val string = JSON_PRETTY.encodeToString(Name.serializer(), name)
|
||||||
val restored = JSON_PLAIN.parse(Name.serializer(), string)
|
val restored = JSON_PLAIN.decodeFromString(Name.serializer(), string)
|
||||||
assertEquals(restored, name)
|
assertEquals(name, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
@Test
|
@Test
|
||||||
fun testMetaItemDescriptor() {
|
fun testMetaItemDescriptor() {
|
||||||
val descriptor = MetaItem.serializer(MetaSerializer).descriptor.getElementDescriptor(0)
|
val descriptor = MetaItem.serializer(MetaSerializer).descriptor.getElementDescriptor(0)
|
||||||
|
println(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,5 +3,5 @@ package hep.dataforge.io
|
|||||||
import kotlinx.io.ByteArrayInput
|
import kotlinx.io.ByteArrayInput
|
||||||
import kotlinx.io.use
|
import kotlinx.io.use
|
||||||
|
|
||||||
fun <T : Any> IOFormat<T>.toByteArray(obj: T): ByteArray = buildByteArray { writeObject(obj) }
|
fun <T : Any> IOFormat<T>.writeToByteArray(obj: T): ByteArray = buildByteArray { writeObject(this, obj) }
|
||||||
fun <T : Any> IOFormat<T>.readByteArray(array: ByteArray): T = ByteArrayInput(array).use { it.readObject() }
|
fun <T : Any> IOFormat<T>.readFromByteArray(array: ByteArray): T = ByteArrayInput(array).use { readObject(it) }
|
@ -11,12 +11,12 @@ import java.nio.file.StandardOpenOption
|
|||||||
import kotlin.reflect.full.isSuperclassOf
|
import kotlin.reflect.full.isSuperclassOf
|
||||||
import kotlin.streams.asSequence
|
import kotlin.streams.asSequence
|
||||||
|
|
||||||
fun <R> Path.read(block: Input.() -> R): R = asBinary().read(block = block)
|
public fun <R> Path.read(block: Input.() -> R): R = asBinary().read(block = block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a live output to a newly created file. If file does not exist, throws error
|
* Write a live output to a newly created file. If file does not exist, throws error
|
||||||
*/
|
*/
|
||||||
fun Path.write(block: Output.() -> Unit): Unit {
|
public fun Path.write(block: Output.() -> Unit): Unit {
|
||||||
val stream = Files.newOutputStream(this, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)
|
val stream = Files.newOutputStream(this, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)
|
||||||
stream.asOutput().use(block)
|
stream.asOutput().use(block)
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ fun Path.write(block: Output.() -> Unit): Unit {
|
|||||||
/**
|
/**
|
||||||
* Create a new file or append to exiting one with given output [block]
|
* Create a new file or append to exiting one with given output [block]
|
||||||
*/
|
*/
|
||||||
fun Path.append(block: Output.() -> Unit): Unit {
|
public fun Path.append(block: Output.() -> Unit): Unit {
|
||||||
val stream = Files.newOutputStream(
|
val stream = Files.newOutputStream(
|
||||||
this,
|
this,
|
||||||
StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE
|
StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE
|
||||||
@ -35,7 +35,7 @@ fun Path.append(block: Output.() -> Unit): Unit {
|
|||||||
/**
|
/**
|
||||||
* Create a new file or replace existing one using given output [block]
|
* Create a new file or replace existing one using given output [block]
|
||||||
*/
|
*/
|
||||||
fun Path.rewrite(block: Output.() -> Unit): Unit {
|
public fun Path.rewrite(block: Output.() -> Unit): Unit {
|
||||||
val stream = Files.newOutputStream(
|
val stream = Files.newOutputStream(
|
||||||
this,
|
this,
|
||||||
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE
|
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE
|
||||||
@ -43,9 +43,9 @@ fun Path.rewrite(block: Output.() -> Unit): Unit {
|
|||||||
stream.asOutput().use(block)
|
stream.asOutput().use(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
public fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
||||||
val partialEnvelope: PartialEnvelope = asBinary().read {
|
val partialEnvelope: PartialEnvelope = asBinary().read {
|
||||||
format.run { readPartial() }
|
format.run { readPartial(this@read) }
|
||||||
}
|
}
|
||||||
val offset: Int = partialEnvelope.dataOffset.toInt()
|
val offset: Int = partialEnvelope.dataOffset.toInt()
|
||||||
val size: Int = partialEnvelope.dataSize?.toInt() ?: (Files.size(this).toInt() - offset)
|
val size: Int = partialEnvelope.dataSize?.toInt() ?: (Files.size(this).toInt() - offset)
|
||||||
@ -58,7 +58,7 @@ fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
|||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? {
|
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.isSuperclassOf(T::class) } as IOFormat<T>?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,11 @@ inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? {
|
|||||||
* Read file containing meta using given [formatOverride] or file extension to infer meta type.
|
* Read file containing meta using given [formatOverride] or file extension to infer meta type.
|
||||||
* If [path] is a directory search for file starting with `meta` in it
|
* If [path] is a directory search for file starting with `meta` in it
|
||||||
*/
|
*/
|
||||||
fun IOPlugin.readMetaFile(path: Path, formatOverride: MetaFormat? = null, descriptor: NodeDescriptor? = null): Meta {
|
public fun IOPlugin.readMetaFile(
|
||||||
|
path: Path,
|
||||||
|
formatOverride: MetaFormat? = null,
|
||||||
|
descriptor: NodeDescriptor? = null,
|
||||||
|
): Meta {
|
||||||
if (!Files.exists(path)) error("Meta file $path does not exist")
|
if (!Files.exists(path)) error("Meta file $path does not exist")
|
||||||
|
|
||||||
val actualPath: Path = if (Files.isDirectory(path)) {
|
val actualPath: Path = if (Files.isDirectory(path)) {
|
||||||
@ -80,7 +84,7 @@ fun IOPlugin.readMetaFile(path: Path, formatOverride: MetaFormat? = null, descri
|
|||||||
val metaFormat = formatOverride ?: resolveMetaFormat(extension) ?: error("Can't resolve meta format $extension")
|
val metaFormat = formatOverride ?: resolveMetaFormat(extension) ?: error("Can't resolve meta format $extension")
|
||||||
return metaFormat.run {
|
return metaFormat.run {
|
||||||
actualPath.read {
|
actualPath.read {
|
||||||
readMeta(descriptor)
|
readMeta(this, descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,11 +93,11 @@ fun IOPlugin.readMetaFile(path: Path, formatOverride: MetaFormat? = null, descri
|
|||||||
* Write meta to file using [metaFormat]. If [path] is a directory, write a file with name equals name of [metaFormat].
|
* Write meta to file using [metaFormat]. If [path] is a directory, write a file with name equals name of [metaFormat].
|
||||||
* Like "meta.json"
|
* Like "meta.json"
|
||||||
*/
|
*/
|
||||||
fun IOPlugin.writeMetaFile(
|
public fun IOPlugin.writeMetaFile(
|
||||||
path: Path,
|
path: Path,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
metaFormat: MetaFormatFactory = JsonMetaFormat,
|
metaFormat: MetaFormatFactory = JsonMetaFormat,
|
||||||
descriptor: NodeDescriptor? = null
|
descriptor: NodeDescriptor? = null,
|
||||||
) {
|
) {
|
||||||
val actualPath = if (Files.isDirectory(path)) {
|
val actualPath = if (Files.isDirectory(path)) {
|
||||||
path.resolve("@" + metaFormat.name.toString())
|
path.resolve("@" + metaFormat.name.toString())
|
||||||
@ -102,7 +106,7 @@ fun IOPlugin.writeMetaFile(
|
|||||||
}
|
}
|
||||||
metaFormat.run {
|
metaFormat.run {
|
||||||
actualPath.write {
|
actualPath.write {
|
||||||
writeMeta(meta, descriptor)
|
writeMeta(this, meta, descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +115,7 @@ fun IOPlugin.writeMetaFile(
|
|||||||
* Return inferred [EnvelopeFormat] if only one format could read given file. If no format accepts file, return null. If
|
* 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.
|
* multiple formats accepts file, throw an error.
|
||||||
*/
|
*/
|
||||||
fun IOPlugin.peekBinaryFormat(path: Path): EnvelopeFormat? {
|
public fun IOPlugin.peekBinaryFormat(path: Path): EnvelopeFormat? {
|
||||||
val binary = path.asBinary()
|
val binary = path.asBinary()
|
||||||
val formats = envelopeFormatFactories.mapNotNull { factory ->
|
val formats = envelopeFormatFactories.mapNotNull { factory ->
|
||||||
binary.read {
|
binary.read {
|
||||||
@ -126,8 +130,8 @@ fun IOPlugin.peekBinaryFormat(path: Path): EnvelopeFormat? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val IOPlugin.Companion.META_FILE_NAME: String get() = "@meta"
|
public val IOPlugin.Companion.META_FILE_NAME: String get() = "@meta"
|
||||||
val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
|
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.
|
* Read and envelope from file if the file exists, return null if file does not exist.
|
||||||
@ -143,17 +147,18 @@ val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
|
|||||||
* Return null otherwise.
|
* Return null otherwise.
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
fun IOPlugin.readEnvelopeFile(
|
public fun IOPlugin.readEnvelopeFile(
|
||||||
path: Path,
|
path: Path,
|
||||||
readNonEnvelopes: Boolean = false,
|
readNonEnvelopes: Boolean = false,
|
||||||
formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat
|
formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat,
|
||||||
): Envelope? {
|
): Envelope? {
|
||||||
if (!Files.exists(path)) return null
|
if (!Files.exists(path)) return null
|
||||||
|
|
||||||
//read two-files directory
|
//read two-files directory
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
val metaFile = Files.list(path).asSequence()
|
val metaFile = Files.list(path).asSequence().singleOrNull {
|
||||||
.singleOrNull { it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME) }
|
it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
val meta = if (metaFile == null) {
|
val meta = if (metaFile == null) {
|
||||||
Meta.EMPTY
|
Meta.EMPTY
|
||||||
@ -182,9 +187,9 @@ fun IOPlugin.readEnvelopeFile(
|
|||||||
/**
|
/**
|
||||||
* Write a binary into file. Throws an error if file already exists
|
* Write a binary into file. Throws an error if file already exists
|
||||||
*/
|
*/
|
||||||
fun <T : Any> IOFormat<T>.writeToFile(path: Path, obj: T) {
|
public fun <T : Any> IOFormat<T>.writeToFile(path: Path, obj: T) {
|
||||||
path.write {
|
path.write {
|
||||||
writeObject(obj)
|
writeObject(this, obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,16 +197,14 @@ fun <T : Any> IOFormat<T>.writeToFile(path: Path, obj: T) {
|
|||||||
* Write envelope file to given [path] using [envelopeFormat] and optional [metaFormat]
|
* Write envelope file to given [path] using [envelopeFormat] and optional [metaFormat]
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
fun IOPlugin.writeEnvelopeFile(
|
public fun IOPlugin.writeEnvelopeFile(
|
||||||
path: Path,
|
path: Path,
|
||||||
envelope: Envelope,
|
envelope: Envelope,
|
||||||
envelopeFormat: EnvelopeFormat = TaggedEnvelopeFormat,
|
envelopeFormat: EnvelopeFormat = TaggedEnvelopeFormat,
|
||||||
metaFormat: MetaFormatFactory? = null
|
metaFormat: MetaFormatFactory? = null,
|
||||||
) {
|
) {
|
||||||
path.rewrite {
|
path.rewrite {
|
||||||
with(envelopeFormat) {
|
envelopeFormat.writeEnvelope(this, envelope, metaFormat ?: envelopeFormat.defaultMetaFormat)
|
||||||
writeEnvelope(envelope, metaFormat ?: envelopeFormat.defaultMetaFormat)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,10 +212,10 @@ fun IOPlugin.writeEnvelopeFile(
|
|||||||
* Write separate meta and data files to given directory [path]
|
* Write separate meta and data files to given directory [path]
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
fun IOPlugin.writeEnvelopeDirectory(
|
public fun IOPlugin.writeEnvelopeDirectory(
|
||||||
path: Path,
|
path: Path,
|
||||||
envelope: Envelope,
|
envelope: Envelope,
|
||||||
metaFormat: MetaFormatFactory = JsonMetaFormat
|
metaFormat: MetaFormatFactory = JsonMetaFormat,
|
||||||
) {
|
) {
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
Files.createDirectories(path)
|
Files.createDirectories(path)
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package hep.dataforge.io
|
|
||||||
|
|
||||||
import hep.dataforge.io.functions.FunctionServer
|
|
||||||
import hep.dataforge.io.functions.function
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.full.isSuperclassOf
|
|
||||||
|
|
||||||
|
|
||||||
fun IOPlugin.resolveIOFormatName(type: KClass<*>): Name {
|
|
||||||
return ioFormatFactories.find { it.type.isSuperclassOf(type) }?.name
|
|
||||||
?: error("Can't resolve IOFormat for type $type")
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any, reified R : Any> IOPlugin.generateFunctionMeta(functionName: String): Meta = Meta {
|
|
||||||
FunctionServer.FUNCTION_NAME_KEY put functionName
|
|
||||||
FunctionServer.INPUT_FORMAT_KEY put resolveIOFormatName(T::class).toString()
|
|
||||||
FunctionServer.OUTPUT_FORMAT_KEY put resolveIOFormatName(R::class).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any, reified R : Any> FunctionServer.function(
|
|
||||||
functionName: String
|
|
||||||
): (suspend (T) -> R) {
|
|
||||||
val plugin = context.plugins.get<IOPlugin>() ?: error("IO plugin not loaded")
|
|
||||||
val meta = plugin.generateFunctionMeta<T, R>(functionName)
|
|
||||||
return function(meta)
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.io.tcp
|
package hep.dataforge.io
|
||||||
|
|
||||||
import kotlinx.io.*
|
import kotlinx.io.*
|
||||||
import kotlinx.io.buffer.Buffer
|
import kotlinx.io.buffer.Buffer
|
||||||
@ -30,16 +30,16 @@ private class BlockingStreamInput(val source: InputStream) : Input() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <R> InputStream.read(size: Int, block: Input.() -> R): R {
|
public fun <R> InputStream.read(size: Int, block: Input.() -> R): R {
|
||||||
val buffer = ByteArray(size)
|
val buffer = ByteArray(size)
|
||||||
read(buffer)
|
read(buffer)
|
||||||
return buffer.asBinary().read(block = block)
|
return buffer.asBinary().read(block = block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <R> InputStream.read(block: Input.() -> R): R = asInput().block()
|
public fun <R> InputStream.read(block: Input.() -> R): R = asInput().block()
|
||||||
|
|
||||||
fun <R> InputStream.readBlocking(block: Input.() -> R): R = BlockingStreamInput(this).block()
|
public fun <R> InputStream.readBlocking(block: Input.() -> R): R = BlockingStreamInput(this).block()
|
||||||
|
|
||||||
inline fun OutputStream.write(block: Output.() -> Unit) {
|
public inline fun OutputStream.write(block: Output.() -> Unit) {
|
||||||
asOutput().block()
|
asOutput().block()
|
||||||
}
|
}
|
@ -1,65 +0,0 @@
|
|||||||
package hep.dataforge.io.tcp
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.context.ContextAware
|
|
||||||
import hep.dataforge.io.*
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.net.Socket
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
|
|
||||||
@ExperimentalTime
|
|
||||||
class EnvelopeClient(
|
|
||||||
override val context: Context,
|
|
||||||
val host: String,
|
|
||||||
val port: Int,
|
|
||||||
formatFactory: EnvelopeFormatFactory = TaggedEnvelopeFormat,
|
|
||||||
formatMeta: Meta = Meta.EMPTY
|
|
||||||
) : Responder, ContextAware {
|
|
||||||
|
|
||||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
|
||||||
|
|
||||||
private val format = formatFactory(formatMeta, context = context)
|
|
||||||
|
|
||||||
// private var socket: SocketChannel? = null
|
|
||||||
//
|
|
||||||
// private fun getSocket(): Socket {
|
|
||||||
// val socket = socket ?: Socket(host, port).also { this.socket = it }
|
|
||||||
// return if (socket.isConnected) {
|
|
||||||
// socket
|
|
||||||
// } else {
|
|
||||||
// Socket(host, port).also { this.socket = it }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
suspend fun close() {
|
|
||||||
try {
|
|
||||||
respond(
|
|
||||||
Envelope {
|
|
||||||
type = EnvelopeServer.SHUTDOWN_ENVELOPE_TYPE
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
logger.error { ex }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun respond(request: Envelope): Envelope = withContext(dispatcher) {
|
|
||||||
//val address = InetSocketAddress(host,port)
|
|
||||||
val socket = Socket(host, port)
|
|
||||||
val inputStream = socket.getInputStream()
|
|
||||||
val outputStream = socket.getOutputStream()
|
|
||||||
format.run {
|
|
||||||
outputStream.write {
|
|
||||||
writeObject(request)
|
|
||||||
}
|
|
||||||
logger.debug { "Sent request with type ${request.type} to ${socket.remoteSocketAddress}" }
|
|
||||||
val res = inputStream.readBlocking { readObject() }
|
|
||||||
logger.debug { "Received response with type ${res.type} from ${socket.remoteSocketAddress}" }
|
|
||||||
return@withContext res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
package hep.dataforge.io.tcp
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.context.ContextAware
|
|
||||||
import hep.dataforge.io.EnvelopeFormatFactory
|
|
||||||
import hep.dataforge.io.Responder
|
|
||||||
import hep.dataforge.io.TaggedEnvelopeFormat
|
|
||||||
import hep.dataforge.io.type
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import java.net.ServerSocket
|
|
||||||
import java.net.Socket
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
class EnvelopeServer(
|
|
||||||
override val context: Context,
|
|
||||||
val port: Int,
|
|
||||||
val responder: Responder,
|
|
||||||
val scope: CoroutineScope,
|
|
||||||
formatFactory: EnvelopeFormatFactory = TaggedEnvelopeFormat,
|
|
||||||
formatMeta: Meta = Meta.EMPTY
|
|
||||||
) : ContextAware {
|
|
||||||
|
|
||||||
private var job: Job? = null
|
|
||||||
|
|
||||||
private val format = formatFactory(formatMeta, context = context)
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
if (job == null) {
|
|
||||||
logger.info { "Starting envelope server on port $port" }
|
|
||||||
job = scope.launch(Dispatchers.IO) {
|
|
||||||
val serverSocket = ServerSocket(port)
|
|
||||||
//TODO add handshake and format negotiation
|
|
||||||
while (isActive && !serverSocket.isClosed) {
|
|
||||||
val socket = serverSocket.accept()
|
|
||||||
logger.info { "Accepted connection from ${socket.remoteSocketAddress}" }
|
|
||||||
readSocket(socket)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
logger.info { "Stopping envelope server on port $port" }
|
|
||||||
job?.cancel()
|
|
||||||
job = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// private fun CoroutineScope.readSocket(socket: Socket) {
|
|
||||||
// launch(Dispatchers.IO) {
|
|
||||||
// val input = socket.getInputStream().asInput()
|
|
||||||
// val output = socket.getOutputStream().asOutput()
|
|
||||||
// format.run {
|
|
||||||
// while (isActive && socket.isConnected) {
|
|
||||||
// val request = input.readThis()
|
|
||||||
// logger.debug { "Accepted request with type ${request.type} from ${socket.remoteSocketAddress}" }
|
|
||||||
// if (request.type == SHUTDOWN_ENVELOPE_TYPE) {
|
|
||||||
// //Echo shutdown command
|
|
||||||
// logger.info { "Accepted graceful shutdown signal from ${socket.inetAddress}" }
|
|
||||||
// socket.close()
|
|
||||||
// cancel("Graceful connection shutdown requested by client")
|
|
||||||
// }
|
|
||||||
// val response = responder.respond(request)
|
|
||||||
// output.writeThis(response)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private fun readSocket(socket: Socket) {
|
|
||||||
thread {
|
|
||||||
val inputStream = socket.getInputStream()
|
|
||||||
val outputStream = socket.getOutputStream()
|
|
||||||
format.run {
|
|
||||||
while (socket.isConnected) {
|
|
||||||
val request = inputStream.readBlocking { readObject() }
|
|
||||||
logger.debug { "Accepted request with type ${request.type} from ${socket.remoteSocketAddress}" }
|
|
||||||
if (request.type == SHUTDOWN_ENVELOPE_TYPE) {
|
|
||||||
//Echo shutdown command
|
|
||||||
outputStream.write {
|
|
||||||
writeObject(request)
|
|
||||||
}
|
|
||||||
logger.info { "Accepted graceful shutdown signal from ${socket.inetAddress}" }
|
|
||||||
socket.close()
|
|
||||||
return@thread
|
|
||||||
// cancel("Graceful connection shutdown requested by client")
|
|
||||||
}
|
|
||||||
runBlocking {
|
|
||||||
val response = responder.respond(request)
|
|
||||||
outputStream.write {
|
|
||||||
writeObject(response)
|
|
||||||
}
|
|
||||||
logger.debug { "Sent response with type ${response.type} to ${socket.remoteSocketAddress}" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val SHUTDOWN_ENVELOPE_TYPE = "@shutdown"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
package hep.dataforge.io.tcp
|
|
||||||
|
|
||||||
import hep.dataforge.context.Global
|
|
||||||
import hep.dataforge.io.Envelope
|
|
||||||
import hep.dataforge.io.Responder
|
|
||||||
import hep.dataforge.io.TaggedEnvelopeFormat
|
|
||||||
import hep.dataforge.io.toByteArray
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.io.writeDouble
|
|
||||||
import org.junit.jupiter.api.AfterAll
|
|
||||||
import org.junit.jupiter.api.BeforeAll
|
|
||||||
import org.junit.jupiter.api.Timeout
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
object EchoResponder : Responder {
|
|
||||||
override suspend fun respond(request: Envelope): Envelope {
|
|
||||||
val string = TaggedEnvelopeFormat().run { toByteArray(request).decodeToString() }
|
|
||||||
println("ECHO:")
|
|
||||||
println(string)
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExperimentalTime
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
class EnvelopeServerTest {
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
val echoEnvelopeServer = EnvelopeServer(Global, 7778, EchoResponder, GlobalScope)
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
@JvmStatic
|
|
||||||
fun start() {
|
|
||||||
echoEnvelopeServer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
@JvmStatic
|
|
||||||
fun close() {
|
|
||||||
echoEnvelopeServer.stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Timeout(1)
|
|
||||||
fun doEchoTest() {
|
|
||||||
val request = Envelope {
|
|
||||||
type = "test.echo"
|
|
||||||
meta {
|
|
||||||
"test.value" put 22
|
|
||||||
}
|
|
||||||
data {
|
|
||||||
writeDouble(22.7)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val client = EnvelopeClient(Global, host = "localhost", port = 7778)
|
|
||||||
runBlocking {
|
|
||||||
val response = client.respond(request)
|
|
||||||
|
|
||||||
|
|
||||||
assertEquals(request.meta, response.meta)
|
|
||||||
// assertEquals(request.data?.toBytes()?.decodeToString(), response.data?.toBytes()?.decodeToString())
|
|
||||||
client.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
1015
dataforge-meta/api/dataforge-meta.api
Normal file
1015
dataforge-meta/api/dataforge-meta.api
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,12 @@
|
|||||||
import scientifik.useSerialization
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("ru.mipt.npm.mpp")
|
||||||
|
id("ru.mipt.npm.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
useSerialization()
|
kscience {
|
||||||
|
useSerialization{
|
||||||
|
json()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
description = "Meta definition and basic operations on meta"
|
description = "Meta definition and basic operations on meta"
|
@ -4,25 +4,30 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
//TODO add validator to configuration
|
//TODO add validator to configuration
|
||||||
|
|
||||||
data class MetaListener(
|
public data class MetaListener(
|
||||||
val owner: Any? = null,
|
val owner: Any? = null,
|
||||||
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
interface ObservableMeta : Meta {
|
public interface ObservableMeta : Meta {
|
||||||
fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
|
public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
|
||||||
fun removeListener(owner: Any?)
|
public fun removeListener(owner: Any?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutable meta representing object state
|
* Mutable meta representing object state
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable(Config.Companion::class)
|
||||||
class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
|
||||||
|
|
||||||
private val listeners = HashSet<MetaListener>()
|
private val listeners = HashSet<MetaListener>()
|
||||||
|
|
||||||
@ -46,12 +51,12 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
|||||||
|
|
||||||
override fun replaceItem(key: NameToken, oldItem: MetaItem<Config>?, newItem: MetaItem<Config>?) {
|
override fun replaceItem(key: NameToken, oldItem: MetaItem<Config>?, newItem: MetaItem<Config>?) {
|
||||||
if (newItem == null) {
|
if (newItem == null) {
|
||||||
_items.remove(key)
|
children.remove(key)
|
||||||
if (oldItem != null && oldItem is MetaItem.NodeItem<Config>) {
|
if (oldItem != null && oldItem is MetaItem.NodeItem<Config>) {
|
||||||
oldItem.node.removeListener(this)
|
oldItem.node.removeListener(this)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_items[key] = newItem
|
children[key] = newItem
|
||||||
if (newItem is MetaItem.NodeItem) {
|
if (newItem is MetaItem.NodeItem) {
|
||||||
newItem.node.onChange(this) { name, oldChild, newChild ->
|
newItem.node.onChange(this) { name, oldChild, newChild ->
|
||||||
itemChanged(key + name, oldChild, newChild)
|
itemChanged(key + name, oldChild, newChild)
|
||||||
@ -68,10 +73,9 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
|||||||
|
|
||||||
override fun empty(): Config = Config()
|
override fun empty(): Config = Config()
|
||||||
|
|
||||||
@Serializer(Config::class)
|
public companion object ConfigSerializer : KSerializer<Config> {
|
||||||
companion object ConfigSerializer : KSerializer<Config> {
|
|
||||||
|
|
||||||
fun empty(): Config = Config()
|
public fun empty(): Config = Config()
|
||||||
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
|
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Config {
|
override fun deserialize(decoder: Decoder): Config {
|
||||||
@ -84,9 +88,9 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token]
|
public operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token]
|
||||||
|
|
||||||
fun Meta.asConfig(): Config = this as? Config ?: Config().also { builder ->
|
public fun Meta.asConfig(): Config = this as? Config ?: Config().also { builder ->
|
||||||
this.items.mapValues { entry ->
|
this.items.mapValues { entry ->
|
||||||
val item = entry.value
|
val item = entry.value
|
||||||
builder[entry.key.asName()] = when (item) {
|
builder[entry.key.asName()] = when (item) {
|
||||||
|
@ -1,115 +1,24 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.meta.descriptors.*
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
|
||||||
import hep.dataforge.names.toName
|
|
||||||
import hep.dataforge.values.Value
|
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container that holds a [Config] and a default item provider.
|
* A container that holds a [Config].
|
||||||
* Default item provider could be use for example to reference parent configuration.
|
|
||||||
* It is not possible to know if some property is declared by provider just by looking on [Configurable],
|
|
||||||
* this information should be provided externally.
|
|
||||||
*/
|
*/
|
||||||
interface Configurable : Described, MutableItemProvider {
|
public interface Configurable {
|
||||||
/**
|
/**
|
||||||
* Backing config
|
* Backing config
|
||||||
*/
|
*/
|
||||||
val config: Config
|
public val config: Config
|
||||||
|
|
||||||
/**
|
|
||||||
* Default meta item provider
|
|
||||||
*/
|
|
||||||
fun getDefaultItem(name: Name): MetaItem<*>? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if property with given [name] could be assigned to [value]
|
|
||||||
*/
|
|
||||||
fun validateItem(name: Name, item: MetaItem<*>?): Boolean {
|
|
||||||
val descriptor = descriptor?.get(name)
|
|
||||||
return descriptor?.validateItem(item) ?: true
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor? get() = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a property with default
|
|
||||||
*/
|
|
||||||
override fun getItem(name: Name): MetaItem<*>? =
|
|
||||||
config[name] ?: getDefaultItem(name) ?: descriptor?.get(name)?.defaultItem()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a configurable property
|
|
||||||
*/
|
|
||||||
override fun setItem(name: Name, item: MetaItem<*>?) {
|
|
||||||
if (validateItem(name, item)) {
|
|
||||||
config.setItem(name, item)
|
|
||||||
} else {
|
|
||||||
error("Validation failed for property $name with value $item")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the property to its default value
|
|
||||||
*/
|
|
||||||
fun Configurable.resetProperty(name: Name) {
|
|
||||||
setItem(name, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Configurable.getItem(key: String) = getItem(key.toName())
|
public fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
|
||||||
|
|
||||||
fun Configurable.setItem(name: Name, value: Value?) = setItem(name, value?.let { MetaItem.ValueItem(value) })
|
|
||||||
fun Configurable.setItem(name: Name, meta: Meta?) = setItem(name, meta?.let { MetaItem.NodeItem(meta) })
|
|
||||||
|
|
||||||
fun Configurable.setItem(key: String, item: MetaItem<*>?) = setItem(key.toName(), item)
|
|
||||||
|
|
||||||
fun Configurable.setItem(key: String, value: Value?) = setItem(key, value?.let { MetaItem.ValueItem(value) })
|
|
||||||
fun Configurable.setItem(key: String, meta: Meta?) = setItem(key, meta?.let { MetaItem.NodeItem(meta) })
|
|
||||||
|
|
||||||
fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
|
|
||||||
|
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }
|
public inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }
|
||||||
|
|
||||||
/* Node delegates */
|
/* Node delegates */
|
||||||
|
|
||||||
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> =
|
public fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> = config.node(key)
|
||||||
config.node(key)
|
|
||||||
|
|
||||||
fun MutableItemProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).convert(
|
|
||||||
reader = { it.node },
|
|
||||||
writer = { it?.let { MetaItem.NodeItem(it) } }
|
|
||||||
)
|
|
||||||
|
|
||||||
fun <T : Configurable> Configurable.spec(
|
|
||||||
spec: Specification<T>, key: Name? = null
|
|
||||||
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
|
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
|
|
||||||
val name = key ?: property.name.asName()
|
|
||||||
return config[name].node?.let { spec.wrap(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
|
||||||
val name = key ?: property.name.asName()
|
|
||||||
config[name] = value?.config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Configurable> Configurable.spec(
|
|
||||||
spec: Specification<T>, default: T, key: Name? = null
|
|
||||||
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
|
||||||
val name = key ?: property.name.asName()
|
|
||||||
return config[name].node?.let { spec.wrap(it) } ?: default
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
|
||||||
val name = key ?: property.name.asName()
|
|
||||||
config[name] = value.config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -5,62 +5,107 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
/* Meta delegates */
|
/* Meta delegates */
|
||||||
|
|
||||||
open class ItemDelegate(
|
public typealias ItemDelegate = ReadOnlyProperty<Any?, MetaItem<*>?>
|
||||||
open val owner: ItemProvider,
|
|
||||||
val key: Name? = null,
|
|
||||||
open val default: MetaItem<*>? = null
|
|
||||||
) : ReadOnlyProperty<Any?, MetaItem<*>?> {
|
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
|
|
||||||
return owner.getItem(key ?: property.name.asName()) ?: default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ItemProvider.item(key: Name? = null): ItemDelegate = ItemDelegate(this, key)
|
public fun ItemProvider.item(key: Name? = null): ItemDelegate = ReadOnlyProperty { _, property ->
|
||||||
|
getItem(key ?: property.name.asName())
|
||||||
|
}
|
||||||
|
|
||||||
//TODO add caching for sealed nodes
|
//TODO add caching for sealed nodes
|
||||||
|
|
||||||
|
|
||||||
//Read-only delegates for Metas
|
/**
|
||||||
|
* Apply a converter to this delegate creating a delegate with a custom type
|
||||||
|
*/
|
||||||
|
public fun <R : Any> ItemDelegate.convert(
|
||||||
|
converter: MetaConverter<R>,
|
||||||
|
): ReadOnlyProperty<Any?, R?> = ReadOnlyProperty { thisRef, property ->
|
||||||
|
this@convert.getValue(thisRef, property)?.let(converter::itemToObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public fun <R : Any> ItemDelegate.convert(
|
||||||
|
converter: MetaConverter<R>,
|
||||||
|
default: () -> R,
|
||||||
|
): ReadOnlyProperty<Any?, R> = ReadOnlyProperty<Any?, R> { thisRef, property ->
|
||||||
|
this@convert.getValue(thisRef, property)?.let(converter::itemToObject) ?: default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A converter with a custom reader transformation
|
||||||
|
*/
|
||||||
|
public fun <R> ItemDelegate.convert(
|
||||||
|
reader: (MetaItem<*>?) -> R,
|
||||||
|
): ReadOnlyProperty<Any?, R> = ReadOnlyProperty<Any?, R> { thisRef, property ->
|
||||||
|
this@convert.getValue(thisRef, property).let(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-only delegates for [ItemProvider] */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A property delegate that uses custom key
|
* A property delegate that uses custom key
|
||||||
*/
|
*/
|
||||||
fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> =
|
public fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> =
|
||||||
item(key).convert(MetaConverter.value)
|
item(key).convert(MetaConverter.value)
|
||||||
|
|
||||||
fun ItemProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> =
|
public fun ItemProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> =
|
||||||
item(key).convert(MetaConverter.string)
|
item(key).convert(MetaConverter.string)
|
||||||
|
|
||||||
fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> =
|
public fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> =
|
||||||
item(key).convert(MetaConverter.boolean)
|
item(key).convert(MetaConverter.boolean)
|
||||||
|
|
||||||
fun ItemProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> =
|
public fun ItemProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> =
|
||||||
item(key).convert(MetaConverter.number)
|
item(key).convert(MetaConverter.number)
|
||||||
|
|
||||||
fun ItemProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> =
|
public fun ItemProvider.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> =
|
||||||
|
item(key).convert(MetaConverter.double)
|
||||||
|
|
||||||
|
public fun ItemProvider.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> =
|
||||||
|
item(key).convert(MetaConverter.float)
|
||||||
|
|
||||||
|
public fun ItemProvider.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> =
|
||||||
|
item(key).convert(MetaConverter.int)
|
||||||
|
|
||||||
|
public fun ItemProvider.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> =
|
||||||
|
item(key).convert(MetaConverter.long)
|
||||||
|
|
||||||
|
public fun ItemProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> =
|
||||||
item(key).convert(MetaConverter.meta)
|
item(key).convert(MetaConverter.meta)
|
||||||
|
|
||||||
fun ItemProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> =
|
public fun ItemProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> =
|
||||||
item(key).convert(MetaConverter.string) { default }
|
item(key).convert(MetaConverter.string) { default }
|
||||||
|
|
||||||
fun ItemProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> =
|
public fun ItemProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> =
|
||||||
item(key).convert(MetaConverter.boolean) { default }
|
item(key).convert(MetaConverter.boolean) { default }
|
||||||
|
|
||||||
fun ItemProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> =
|
public fun ItemProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> =
|
||||||
item(key).convert(MetaConverter.number) { default }
|
item(key).convert(MetaConverter.number) { default }
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> ItemProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> =
|
public fun ItemProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> =
|
||||||
|
item(key).convert(MetaConverter.double) { default }
|
||||||
|
|
||||||
|
public fun ItemProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> =
|
||||||
|
item(key).convert(MetaConverter.float) { default }
|
||||||
|
|
||||||
|
public fun ItemProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> =
|
||||||
|
item(key).convert(MetaConverter.int) { default }
|
||||||
|
|
||||||
|
public fun ItemProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> =
|
||||||
|
item(key).convert(MetaConverter.long) { default }
|
||||||
|
|
||||||
|
public inline fun <reified E : Enum<E>> ItemProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> =
|
||||||
item(key).convert(MetaConverter.enum()) { default }
|
item(key).convert(MetaConverter.enum()) { default }
|
||||||
|
|
||||||
fun ItemProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> =
|
public fun ItemProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> =
|
||||||
item(key).convert(MetaConverter.string, default)
|
item(key).convert(MetaConverter.string, default)
|
||||||
|
|
||||||
fun ItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> =
|
public fun ItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> =
|
||||||
item(key).convert(MetaConverter.boolean, default)
|
item(key).convert(MetaConverter.boolean, default)
|
||||||
|
|
||||||
fun ItemProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> =
|
public fun ItemProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> =
|
||||||
item(key).convert(MetaConverter.number, default)
|
item(key).convert(MetaConverter.number, default)
|
||||||
|
@ -4,6 +4,7 @@ package hep.dataforge.meta
|
|||||||
|
|
||||||
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
||||||
import hep.dataforge.meta.descriptors.ItemDescriptor
|
import hep.dataforge.meta.descriptors.ItemDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.ItemDescriptor.Companion.DEFAULT_INDEX_KEY
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.meta.descriptors.ValueDescriptor
|
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
@ -15,7 +16,7 @@ import kotlinx.serialization.json.*
|
|||||||
/**
|
/**
|
||||||
* @param descriptor reserved for custom serialization in future
|
* @param descriptor reserved for custom serialization in future
|
||||||
*/
|
*/
|
||||||
fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
|
public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
|
||||||
return if (isList()) {
|
return if (isList()) {
|
||||||
JsonArray(list.map { it.toJson() })
|
JsonArray(list.map { it.toJson() })
|
||||||
} else {
|
} else {
|
||||||
@ -52,7 +53,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
|||||||
fun addElement(key: String) {
|
fun addElement(key: String) {
|
||||||
val itemDescriptor = descriptor?.items?.get(key)
|
val itemDescriptor = descriptor?.items?.get(key)
|
||||||
val jsonKey = key.toJsonKey(itemDescriptor)
|
val jsonKey = key.toJsonKey(itemDescriptor)
|
||||||
val items: Map<String, MetaItem<*>> = getIndexed(key)
|
val items: Map<String?, MetaItem<*>> = getIndexed(key)
|
||||||
when (items.size) {
|
when (items.size) {
|
||||||
0 -> {
|
0 -> {
|
||||||
//do nothing
|
//do nothing
|
||||||
@ -61,9 +62,9 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
|||||||
elementMap[jsonKey] = items.values.first().toJsonElement(itemDescriptor, null)
|
elementMap[jsonKey] = items.values.first().toJsonElement(itemDescriptor, null)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val array = jsonArray {
|
val array = buildJsonArray {
|
||||||
items.forEach { (index, item) ->
|
items.forEach { (index, item) ->
|
||||||
+item.toJsonElement(itemDescriptor, index)
|
add(item.toJsonElement(itemDescriptor, index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elementMap[jsonKey] = array
|
elementMap[jsonKey] = array
|
||||||
@ -75,32 +76,31 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
|||||||
|
|
||||||
|
|
||||||
if (indexValue != null) {
|
if (indexValue != null) {
|
||||||
val indexKey = descriptor?.indexKey ?: NodeDescriptor.DEFAULT_INDEX_KEY
|
val indexKey = descriptor?.indexKey ?: DEFAULT_INDEX_KEY
|
||||||
elementMap[indexKey] = JsonPrimitive(indexValue)
|
elementMap[indexKey] = JsonPrimitive(indexValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonObject(elementMap)
|
return JsonObject(elementMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject = toJsonWithIndex(descriptor, null)
|
public fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject = toJsonWithIndex(descriptor, null)
|
||||||
|
|
||||||
fun JsonObject.toMeta(descriptor: NodeDescriptor? = null): JsonMeta = JsonMeta(this, descriptor)
|
public fun JsonObject.toMeta(descriptor: NodeDescriptor? = null): JsonMeta = JsonMeta(this, descriptor)
|
||||||
|
|
||||||
fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
|
public fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
JsonNull -> Null
|
JsonNull -> Null
|
||||||
is JsonLiteral -> {
|
else -> {
|
||||||
when (body) {
|
if (isString) {
|
||||||
true -> True
|
StringValue(content)
|
||||||
false -> False
|
} else {
|
||||||
is Number -> NumberValue(body as Number)
|
content.parseValue()
|
||||||
else -> StringValue(content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
|
public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
|
||||||
is JsonPrimitive -> {
|
is JsonPrimitive -> {
|
||||||
val value = this.toValue(descriptor as? ValueDescriptor)
|
val value = this.toValue(descriptor as? ValueDescriptor)
|
||||||
MetaItem.ValueItem(value)
|
MetaItem.ValueItem(value)
|
||||||
@ -122,7 +122,7 @@ fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMet
|
|||||||
MetaItem.ValueItem(value)
|
MetaItem.ValueItem(value)
|
||||||
} else {
|
} else {
|
||||||
//We can't return multiple items therefore we create top level node
|
//We can't return multiple items therefore we create top level node
|
||||||
json { JSON_ARRAY_KEY to this@toMetaItem }.toMetaItem(descriptor)
|
buildJsonObject { put(JSON_ARRAY_KEY, this@toMetaItem) }.toMetaItem(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMet
|
|||||||
/**
|
/**
|
||||||
* A meta wrapping json object
|
* A meta wrapping json object
|
||||||
*/
|
*/
|
||||||
class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : MetaBase() {
|
public class JsonMeta(private val json: JsonObject, private val descriptor: NodeDescriptor? = null) : MetaBase() {
|
||||||
|
|
||||||
private fun buildItems(): Map<NameToken, MetaItem<JsonMeta>> {
|
private fun buildItems(): Map<NameToken, MetaItem<JsonMeta>> {
|
||||||
val map = LinkedHashMap<NameToken, MetaItem<JsonMeta>>()
|
val map = LinkedHashMap<NameToken, MetaItem<JsonMeta>>()
|
||||||
@ -159,9 +159,9 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
|
|||||||
)
|
)
|
||||||
map[key] = MetaItem.ValueItem(listValue)
|
map[key] = MetaItem.ValueItem(listValue)
|
||||||
} else value.forEachIndexed { index, jsonElement ->
|
} else value.forEachIndexed { index, jsonElement ->
|
||||||
val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: NodeDescriptor.DEFAULT_INDEX_KEY
|
val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: DEFAULT_INDEX_KEY
|
||||||
val indexValue: String = (jsonElement as? JsonObject)
|
val indexValue: String = (jsonElement as? JsonObject)
|
||||||
?.get(indexKey)?.contentOrNull
|
?.get(indexKey)?.jsonPrimitive?.contentOrNull
|
||||||
?: index.toString() //In case index is non-string, the backward transformation will be broken.
|
?: index.toString() //In case index is non-string, the backward transformation will be broken.
|
||||||
|
|
||||||
val token = key.withIndex(indexValue)
|
val token = key.withIndex(indexValue)
|
||||||
@ -174,10 +174,10 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
|
|||||||
|
|
||||||
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy(::buildItems)
|
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy(::buildItems)
|
||||||
|
|
||||||
companion object{
|
public companion object {
|
||||||
/**
|
/**
|
||||||
* A key representing top-level json array of nodes, which could not be directly represented by a meta node
|
* A key representing top-level json array of nodes, which could not be directly represented by a meta node
|
||||||
*/
|
*/
|
||||||
const val JSON_ARRAY_KEY = "@jsonArray"
|
public const val JSON_ARRAY_KEY: String = "@jsonArray"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,9 +7,9 @@ import hep.dataforge.names.NameToken
|
|||||||
* A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Scheme].
|
* A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Scheme].
|
||||||
* If [layers] list contains a [Laminate] it is flat-mapped.
|
* If [layers] list contains a [Laminate] it is flat-mapped.
|
||||||
*/
|
*/
|
||||||
class Laminate(layers: List<Meta>) : MetaBase() {
|
public class Laminate(layers: List<Meta>) : MetaBase() {
|
||||||
|
|
||||||
val layers: List<Meta> = layers.flatMap {
|
public val layers: List<Meta> = layers.flatMap {
|
||||||
if (it is Laminate) {
|
if (it is Laminate) {
|
||||||
it.layers
|
it.layers
|
||||||
} else {
|
} else {
|
||||||
@ -17,8 +17,6 @@ class Laminate(layers: List<Meta>) : MetaBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(vararg layers: Meta?) : this(layers.filterNotNull())
|
|
||||||
|
|
||||||
override val items: Map<NameToken, MetaItem<Meta>> by lazy {
|
override val items: Map<NameToken, MetaItem<Meta>> by lazy {
|
||||||
layers.map { it.items.keys }.flatten().associateWith { key ->
|
layers.map { it.items.keys }.flatten().associateWith { key ->
|
||||||
layers.asSequence().map { it.items[key] }.filterNotNull().let(replaceRule)
|
layers.asSequence().map { it.items[key] }.filterNotNull().let(replaceRule)
|
||||||
@ -28,21 +26,21 @@ class Laminate(layers: List<Meta>) : MetaBase() {
|
|||||||
/**
|
/**
|
||||||
* Generate sealed meta using [mergeRule]
|
* Generate sealed meta using [mergeRule]
|
||||||
*/
|
*/
|
||||||
fun merge(): SealedMeta {
|
public fun merge(): SealedMeta {
|
||||||
val items = layers.map { it.items.keys }.flatten().associateWith { key ->
|
val items = layers.map { it.items.keys }.flatten().associateWith { key ->
|
||||||
layers.asSequence().map { it.items[key] }.filterNotNull().merge()
|
layers.asSequence().map { it.items[key] }.filterNotNull().merge()
|
||||||
}
|
}
|
||||||
return SealedMeta(items)
|
return SealedMeta(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default rule which always uses the first found item in sequence alongside with its children.
|
* The default rule which always uses the first found item in sequence alongside with its children.
|
||||||
*
|
*
|
||||||
* TODO add picture
|
* TODO add picture
|
||||||
*/
|
*/
|
||||||
val replaceRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.first().seal() }
|
public val replaceRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.first().seal() }
|
||||||
|
|
||||||
private fun Sequence<MetaItem<*>>.merge(): MetaItem<SealedMeta> {
|
private fun Sequence<MetaItem<*>>.merge(): MetaItem<SealedMeta> {
|
||||||
return when {
|
return when {
|
||||||
@ -76,14 +74,17 @@ class Laminate(layers: List<Meta>) : MetaBase() {
|
|||||||
* The values a replaced but meta children are joined
|
* The values a replaced but meta children are joined
|
||||||
* TODO add picture
|
* TODO add picture
|
||||||
*/
|
*/
|
||||||
val mergeRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.merge() }
|
public val mergeRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.merge() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
|
public fun Laminate(vararg layers: Meta?): Laminate = Laminate(layers.filterNotNull())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performance optimized version of get method
|
* Performance optimized version of get method
|
||||||
*/
|
*/
|
||||||
fun Laminate.getFirst(name: Name): MetaItem<*>? {
|
public fun Laminate.getFirst(name: Name): MetaItem<*>? {
|
||||||
layers.forEach { layer ->
|
layers.forEach { layer ->
|
||||||
layer[name]?.let { return it }
|
layer[name]?.let { return it }
|
||||||
}
|
}
|
||||||
@ -93,11 +94,11 @@ fun Laminate.getFirst(name: Name): MetaItem<*>? {
|
|||||||
/**
|
/**
|
||||||
* Create a new [Laminate] adding given layer to the top
|
* Create a new [Laminate] adding given layer to the top
|
||||||
*/
|
*/
|
||||||
fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
public fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new [Laminate] adding given layer to the bottom
|
* Create a new [Laminate] adding given layer to the bottom
|
||||||
*/
|
*/
|
||||||
fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
public fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
||||||
|
|
||||||
//TODO add custom rules for Laminate merge
|
//TODO add custom rules for Laminate merge
|
||||||
|
@ -4,8 +4,12 @@ import hep.dataforge.meta.Meta.Companion.VALUE_KEY
|
|||||||
import hep.dataforge.meta.MetaItem.NodeItem
|
import hep.dataforge.meta.MetaItem.NodeItem
|
||||||
import hep.dataforge.meta.MetaItem.ValueItem
|
import hep.dataforge.meta.MetaItem.ValueItem
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.values.*
|
import hep.dataforge.values.EnumValue
|
||||||
import kotlinx.serialization.*
|
import hep.dataforge.values.Null
|
||||||
|
import hep.dataforge.values.Value
|
||||||
|
import hep.dataforge.values.boolean
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,28 +17,17 @@ import kotlinx.serialization.*
|
|||||||
* * a [ValueItem] (leaf)
|
* * a [ValueItem] (leaf)
|
||||||
* * a [NodeItem] (node)
|
* * a [NodeItem] (node)
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable(MetaItemSerializer::class)
|
||||||
sealed class MetaItem<out M : Meta> {
|
public sealed class MetaItem<out M : Meta>() {
|
||||||
|
|
||||||
abstract override fun equals(other: Any?): Boolean
|
abstract override fun equals(other: Any?): Boolean
|
||||||
|
|
||||||
abstract override fun hashCode(): Int
|
abstract override fun hashCode(): Int
|
||||||
|
|
||||||
@Serializable
|
@Serializable(MetaItemSerializer::class)
|
||||||
class ValueItem(val value: Value) : MetaItem<Nothing>() {
|
public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
|
||||||
override fun toString(): String = value.toString()
|
override fun toString(): String = value.toString()
|
||||||
|
|
||||||
@Serializer(ValueItem::class)
|
|
||||||
companion object : KSerializer<ValueItem> {
|
|
||||||
override val descriptor: SerialDescriptor get() = ValueSerializer.descriptor
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): ValueItem = ValueItem(ValueSerializer.deserialize(decoder))
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: ValueItem) {
|
|
||||||
ValueSerializer.serialize(encoder, value.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return this.value == (other as? ValueItem)?.value
|
return this.value == (other as? ValueItem)?.value
|
||||||
}
|
}
|
||||||
@ -44,29 +37,18 @@ sealed class MetaItem<out M : Meta> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable(MetaItemSerializer::class)
|
||||||
class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) val node: M) : MetaItem<M>() {
|
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
|
//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 toString(): String = node.toString()
|
||||||
|
|
||||||
@Serializer(NodeItem::class)
|
|
||||||
companion object : KSerializer<NodeItem<out Meta>> {
|
|
||||||
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): NodeItem<*> = NodeItem(MetaSerializer.deserialize(decoder))
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: NodeItem<*>) {
|
|
||||||
MetaSerializer.serialize(encoder, value.node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = node == (other as? NodeItem<*>)?.node
|
override fun equals(other: Any?): Boolean = node == (other as? NodeItem<*>)?.node
|
||||||
|
|
||||||
override fun hashCode(): Int = node.hashCode()
|
override fun hashCode(): Int = node.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
fun of(arg: Any?): MetaItem<*> {
|
public fun of(arg: Any?): MetaItem<*> {
|
||||||
return when (arg) {
|
return when (arg) {
|
||||||
null -> ValueItem(Null)
|
null -> ValueItem(Null)
|
||||||
is MetaItem<*> -> arg
|
is MetaItem<*> -> arg
|
||||||
@ -77,16 +59,24 @@ sealed class MetaItem<out M : Meta> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
* 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.
|
* Meaning that two states with the same meta are equal.
|
||||||
*/
|
*/
|
||||||
interface MetaRepr {
|
@Serializable(MetaSerializer::class)
|
||||||
fun toMeta(): Meta
|
public interface MetaRepr {
|
||||||
|
public fun toMeta(): Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemProvider{
|
public fun interface ItemProvider {
|
||||||
fun getItem(name: Name): MetaItem<*>?
|
public fun getItem(name: Name): MetaItem<*>?
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val EMPTY: ItemProvider = ItemProvider { null }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,15 +86,15 @@ interface ItemProvider{
|
|||||||
*
|
*
|
||||||
* * Same name siblings are supported via elements with the same [Name] but different queries
|
* * Same name siblings are supported via elements with the same [Name] but different queries
|
||||||
*/
|
*/
|
||||||
interface Meta : MetaRepr, ItemProvider {
|
public interface Meta : MetaRepr, ItemProvider {
|
||||||
/**
|
/**
|
||||||
* Top level items of meta tree
|
* Top level items of meta tree
|
||||||
*/
|
*/
|
||||||
val items: Map<NameToken, MetaItem<*>>
|
public val items: Map<NameToken, MetaItem<*>>
|
||||||
|
|
||||||
override fun getItem(name: Name): MetaItem<*>? {
|
override fun getItem(name: Name): MetaItem<*>? {
|
||||||
if (name.isEmpty()) return NodeItem(this)
|
if (name.isEmpty()) return NodeItem(this)
|
||||||
return name.first()?.let { token ->
|
return name.firstOrNull()?.let { token ->
|
||||||
val tail = name.cutFirst()
|
val tail = name.cutFirst()
|
||||||
when (tail.length) {
|
when (tail.length) {
|
||||||
0 -> items[token]
|
0 -> items[token]
|
||||||
@ -121,15 +111,15 @@ interface Meta : MetaRepr, ItemProvider {
|
|||||||
|
|
||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val TYPE = "meta"
|
public const val TYPE: String = "meta"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key for single value node
|
* A key for single value node
|
||||||
*/
|
*/
|
||||||
const val VALUE_KEY = "@value"
|
public const val VALUE_KEY: String = "@value"
|
||||||
|
|
||||||
val EMPTY: Meta = object: MetaBase() {
|
public val EMPTY: Meta = object : MetaBase() {
|
||||||
override val items: Map<NameToken, MetaItem<*>> = emptyMap()
|
override val items: Map<NameToken, MetaItem<*>> = emptyMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,19 +132,19 @@ interface Meta : MetaRepr, ItemProvider {
|
|||||||
*
|
*
|
||||||
* If [name] is empty return current [Meta] as a [NodeItem]
|
* If [name] is empty return current [Meta] as a [NodeItem]
|
||||||
*/
|
*/
|
||||||
operator fun Meta?.get(name: Name): MetaItem<*>? = this?.getItem(name)
|
public operator fun Meta?.get(name: Name): MetaItem<*>? = this?.getItem(name)
|
||||||
|
|
||||||
operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token)
|
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]
|
* Parse [Name] from [key] using full name notation and pass it to [Meta.get]
|
||||||
*/
|
*/
|
||||||
operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
|
public operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a sequence of [Name]-[Value] pairs
|
* Get a sequence of [Name]-[Value] pairs
|
||||||
*/
|
*/
|
||||||
fun Meta.values(): Sequence<Pair<Name, Value>> {
|
public fun Meta.values(): Sequence<Pair<Name, Value>> {
|
||||||
return items.asSequence().flatMap { (key, item) ->
|
return items.asSequence().flatMap { (key, item) ->
|
||||||
when (item) {
|
when (item) {
|
||||||
is ValueItem -> sequenceOf(key.asName() to item.value)
|
is ValueItem -> sequenceOf(key.asName() to item.value)
|
||||||
@ -166,7 +156,7 @@ fun Meta.values(): Sequence<Pair<Name, Value>> {
|
|||||||
/**
|
/**
|
||||||
* Get a sequence of all [Name]-[MetaItem] pairs for all items including nodes
|
* Get a sequence of all [Name]-[MetaItem] pairs for all items including nodes
|
||||||
*/
|
*/
|
||||||
fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
|
public fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
|
||||||
return sequence {
|
return sequence {
|
||||||
items.forEach { (key, item) ->
|
items.forEach { (key, item) ->
|
||||||
yield(key.asName() to item)
|
yield(key.asName() to item)
|
||||||
@ -179,33 +169,33 @@ fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Meta.iterator(): Iterator<Pair<Name, MetaItem<*>>> = sequence().iterator()
|
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
|
* A meta node that ensures that all of its descendants has at least the same type
|
||||||
*/
|
*/
|
||||||
interface MetaNode<out M : MetaNode<M>> : Meta {
|
public interface MetaNode<out M : MetaNode<M>> : Meta {
|
||||||
override val items: Map<NameToken, MetaItem<M>>
|
override val items: Map<NameToken, MetaItem<M>>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The same as [Meta.get], but with specific node type
|
* The same as [Meta.get], but with specific node type
|
||||||
*/
|
*/
|
||||||
operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) {
|
public operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if (this == null) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
|
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
|
||||||
(this as Meta).get(name) as MetaItem<M>? // Do not change
|
(this as Meta).get(name) as MetaItem<M>? // Do not change
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
|
public operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
|
||||||
|
|
||||||
operator fun <M : MetaNode<M>> M?.get(key: NameToken): MetaItem<M>? = this[key.asName()]
|
public operator fun <M : MetaNode<M>> M?.get(key: NameToken): MetaItem<M>? = this[key.asName()]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equals, hashcode and to string for any meta
|
* Equals, hashcode and to string for any meta
|
||||||
*/
|
*/
|
||||||
abstract class MetaBase : Meta {
|
public abstract class MetaBase : Meta {
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = if (other is Meta) {
|
override fun equals(other: Any?): Boolean = if (other is Meta) {
|
||||||
this.items == other.items
|
this.items == other.items
|
||||||
@ -215,30 +205,33 @@ abstract class MetaBase : Meta {
|
|||||||
|
|
||||||
override fun hashCode(): Int = items.hashCode()
|
override fun hashCode(): Int = items.hashCode()
|
||||||
|
|
||||||
override fun toString(): String = JSON_PRETTY.stringify(MetaSerializer, this)
|
override fun toString(): String = Json {
|
||||||
|
prettyPrint = true
|
||||||
|
useArrayPolymorphism = true
|
||||||
|
}.encodeToString(MetaSerializer, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equals and hash code implementation for meta node
|
* Equals and hash code implementation for meta node
|
||||||
*/
|
*/
|
||||||
abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase()
|
public abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The meta implementation which is guaranteed to be immutable.
|
* The meta implementation which is guaranteed to be immutable.
|
||||||
*
|
*
|
||||||
* If the argument is possibly mutable node, it is copied on creation
|
* If the argument is possibly mutable node, it is copied on creation
|
||||||
*/
|
*/
|
||||||
class SealedMeta internal constructor(
|
public class SealedMeta internal constructor(
|
||||||
override val items: Map<NameToken, MetaItem<SealedMeta>>
|
override val items: Map<NameToken, MetaItem<SealedMeta>>,
|
||||||
) : AbstractMetaNode<SealedMeta>()
|
) : AbstractMetaNode<SealedMeta>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate sealed node from [this]. If it is already sealed return it as is
|
* Generate sealed node from [this]. If it is already sealed return it as is
|
||||||
*/
|
*/
|
||||||
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
|
public fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
public fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
||||||
is ValueItem -> this
|
is ValueItem -> this
|
||||||
is NodeItem -> NodeItem(node.seal())
|
is NodeItem -> NodeItem(node.seal())
|
||||||
}
|
}
|
||||||
@ -246,32 +239,32 @@ fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
|||||||
/**
|
/**
|
||||||
* Unsafe methods to access values and nodes directly from [MetaItem]
|
* Unsafe methods to access values and nodes directly from [MetaItem]
|
||||||
*/
|
*/
|
||||||
val MetaItem<*>?.value: Value?
|
public val MetaItem<*>?.value: Value?
|
||||||
get() = (this as? ValueItem)?.value
|
get() = (this as? ValueItem)?.value
|
||||||
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
|
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
|
||||||
|
|
||||||
val MetaItem<*>?.string get() = value?.string
|
public val MetaItem<*>?.string: String? get() = value?.string
|
||||||
val MetaItem<*>?.boolean get() = value?.boolean
|
public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean
|
||||||
val MetaItem<*>?.number get() = value?.number
|
public val MetaItem<*>?.number: Number? get() = value?.number
|
||||||
val MetaItem<*>?.double get() = number?.toDouble()
|
public val MetaItem<*>?.double: Double? get() = number?.toDouble()
|
||||||
val MetaItem<*>?.float get() = number?.toFloat()
|
public val MetaItem<*>?.float: Float? get() = number?.toFloat()
|
||||||
val MetaItem<*>?.int get() = number?.toInt()
|
public val MetaItem<*>?.int: Int? get() = number?.toInt()
|
||||||
val MetaItem<*>?.long get() = number?.toLong()
|
public val MetaItem<*>?.long: Long? get() = number?.toLong()
|
||||||
val MetaItem<*>?.short get() = number?.toShort()
|
public val MetaItem<*>?.short: Short? get() = number?.toShort()
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> MetaItem<*>?.enum(): E? = if (this is ValueItem && this.value is EnumValue<*>) {
|
public inline fun <reified E : Enum<E>> MetaItem<*>?.enum(): E? = if (this is ValueItem && this.value is EnumValue<*>) {
|
||||||
this.value.value as E
|
this.value.value as E
|
||||||
} else {
|
} else {
|
||||||
string?.let { enumValueOf<E>(it) }
|
string?.let { enumValueOf<E>(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val MetaItem<*>?.stringList get() = value?.list?.map { it.string } ?: emptyList()
|
public val MetaItem<*>.stringList: List<String>? get() = value?.list?.map { it.string }
|
||||||
|
|
||||||
val <M : Meta> MetaItem<M>?.node: M?
|
public val <M : Meta> MetaItem<M>?.node: M?
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
null -> null
|
null -> null
|
||||||
is ValueItem -> null//error("Trying to interpret value meta item as node item")
|
is ValueItem -> null//error("Trying to interpret value meta item as node item")
|
||||||
is NodeItem -> node
|
is NodeItem -> node
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.isEmpty() = this === Meta.EMPTY || this.items.isEmpty()
|
public fun Meta.isEmpty(): Boolean = this === Meta.EMPTY || this.items.isEmpty()
|
@ -11,113 +11,109 @@ import kotlin.jvm.JvmName
|
|||||||
* DSL builder for meta. Is not intended to store mutable state
|
* DSL builder for meta. Is not intended to store mutable state
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
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.builder()
|
||||||
override fun empty(): MetaBuilder = MetaBuilder()
|
override fun empty(): MetaBuilder = MetaBuilder()
|
||||||
|
|
||||||
infix fun String.put(item: MetaItem<*>?) {
|
public infix fun String.put(item: MetaItem<*>?) {
|
||||||
set(this, item)
|
set(this, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(value: Value?) {
|
public infix fun String.put(value: Value?) {
|
||||||
set(this, value)
|
set(this, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(string: String?) {
|
public infix fun String.put(string: String?) {
|
||||||
set(this, string?.asValue())
|
set(this, string?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(number: Number?) {
|
public infix fun String.put(number: Number?) {
|
||||||
set(this, number?.asValue())
|
set(this, number?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(boolean: Boolean?) {
|
public infix fun String.put(boolean: Boolean?) {
|
||||||
set(this, boolean?.asValue())
|
set(this, boolean?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(enum: Enum<*>) {
|
public infix fun String.put(enum: Enum<*>) {
|
||||||
set(this, EnumValue(enum))
|
set(this, EnumValue(enum))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putValues")
|
@JvmName("putValues")
|
||||||
infix fun String.put(iterable: Iterable<Value>) {
|
public infix fun String.put(iterable: Iterable<Value>) {
|
||||||
set(this, iterable.asValue())
|
set(this, iterable.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putNumbers")
|
@JvmName("putNumbers")
|
||||||
infix fun String.put(iterable: Iterable<Number>) {
|
public infix fun String.put(iterable: Iterable<Number>) {
|
||||||
set(this, iterable.map { it.asValue() }.asValue())
|
set(this, iterable.map { it.asValue() }.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putStrings")
|
@JvmName("putStrings")
|
||||||
infix fun String.put(iterable: Iterable<String>) {
|
public infix fun String.put(iterable: Iterable<String>) {
|
||||||
set(this, iterable.map { it.asValue() }.asValue())
|
set(this, iterable.map { it.asValue() }.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(array: DoubleArray) {
|
public infix fun String.put(array: DoubleArray) {
|
||||||
set(this, array.asValue())
|
set(this, array.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.putValue(any: Any?) {
|
public infix fun String.put(meta: Meta?) {
|
||||||
set(this, Value.of(any))
|
|
||||||
}
|
|
||||||
|
|
||||||
infix fun String.put(meta: Meta?) {
|
|
||||||
this@MetaBuilder[this] = meta
|
this@MetaBuilder[this] = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(repr: MetaRepr?) {
|
public infix fun String.put(repr: MetaRepr?) {
|
||||||
set(this, repr?.toMeta())
|
set(this, repr?.toMeta())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putMetas")
|
@JvmName("putMetas")
|
||||||
infix fun String.put(value: Iterable<Meta>) {
|
public infix fun String.put(value: Iterable<Meta>) {
|
||||||
this@MetaBuilder[this] = value.toList()
|
set(this,value.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) {
|
public infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) {
|
||||||
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
|
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(value: Value?) {
|
public infix fun Name.put(value: Value?) {
|
||||||
set(this, value)
|
set(this, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(string: String?) {
|
public infix fun Name.put(string: String?) {
|
||||||
set(this, string?.asValue())
|
set(this, string?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(number: Number?) {
|
public infix fun Name.put(number: Number?) {
|
||||||
set(this, number?.asValue())
|
set(this, number?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(boolean: Boolean?) {
|
public infix fun Name.put(boolean: Boolean?) {
|
||||||
set(this, boolean?.asValue())
|
set(this, boolean?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(enum: Enum<*>) {
|
public infix fun Name.put(enum: Enum<*>) {
|
||||||
set(this, EnumValue(enum))
|
set(this, EnumValue(enum))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putValues")
|
@JvmName("putValues")
|
||||||
infix fun Name.put(iterable: Iterable<Value>) {
|
public infix fun Name.put(iterable: Iterable<Value>) {
|
||||||
set(this, iterable.asValue())
|
set(this, iterable.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(meta: Meta?) {
|
public infix fun Name.put(meta: Meta?) {
|
||||||
this@MetaBuilder[this] = meta
|
this@MetaBuilder[this] = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(repr: MetaRepr?) {
|
public infix fun Name.put(repr: MetaRepr?) {
|
||||||
set(this, repr?.toMeta())
|
set(this, repr?.toMeta())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("putMetas")
|
@JvmName("putMetas")
|
||||||
infix fun Name.put(value: Iterable<Meta>) {
|
public infix fun Name.put(value: Iterable<Meta>) {
|
||||||
this@MetaBuilder[this] = value.toList()
|
set(this, value.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun Name.put(metaBuilder: MetaBuilder.() -> Unit) {
|
public infix fun Name.put(metaBuilder: MetaBuilder.() -> Unit) {
|
||||||
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
|
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +121,7 @@ class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
|||||||
/**
|
/**
|
||||||
* For safety, builder always copies the initial meta even if it is builder itself
|
* For safety, builder always copies the initial meta even if it is builder itself
|
||||||
*/
|
*/
|
||||||
fun Meta.builder(): MetaBuilder {
|
public fun Meta.builder(): MetaBuilder {
|
||||||
return MetaBuilder().also { builder ->
|
return MetaBuilder().also { builder ->
|
||||||
items.mapValues { entry ->
|
items.mapValues { entry ->
|
||||||
val item = entry.value
|
val item = entry.value
|
||||||
@ -140,16 +136,10 @@ fun Meta.builder(): MetaBuilder {
|
|||||||
/**
|
/**
|
||||||
* Create a deep copy of this meta and apply builder to it
|
* Create a deep copy of this meta and apply builder to it
|
||||||
*/
|
*/
|
||||||
fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
|
public fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a [MetaBuilder] using given transformation
|
|
||||||
*/
|
|
||||||
@Deprecated("To be replaced with fake constructor", ReplaceWith("Meta"))
|
|
||||||
fun buildMeta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a [MetaBuilder] using given transformation
|
* Build a [MetaBuilder] using given transformation
|
||||||
*/
|
*/
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
public fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
@ -1,28 +1,68 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import kotlinx.serialization.*
|
import hep.dataforge.values.ValueSerializer
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.MapSerializer
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
import kotlinx.serialization.json.JsonInput
|
import kotlinx.serialization.descriptors.*
|
||||||
import kotlinx.serialization.json.JsonObjectSerializer
|
import kotlinx.serialization.encoding.*
|
||||||
import kotlinx.serialization.json.JsonOutput
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
|
public object MetaItemSerializer : KSerializer<MetaItem<*>> {
|
||||||
|
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
|
||||||
|
element<Boolean>("isNode")
|
||||||
|
element("content", buildSerialDescriptor("MetaItem.content", PolymorphicKind.SEALED))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): MetaItem<*> {
|
||||||
|
decoder.decodeStructure(descriptor) {
|
||||||
|
//Force strict serialization order
|
||||||
|
require(decodeElementIndex(descriptor) == 0) { "Node flag must be first item serialized" }
|
||||||
|
val isNode = decodeBooleanElement(descriptor, 0)
|
||||||
|
require(decodeElementIndex(descriptor) == 1) { "Missing MetaItem content" }
|
||||||
|
val item = if (isNode) {
|
||||||
|
decodeSerializableElement(descriptor,1, MetaSerializer).asMetaItem()
|
||||||
|
} else {
|
||||||
|
decodeSerializableElement(descriptor,1,ValueSerializer).asMetaItem()
|
||||||
|
}
|
||||||
|
require(decodeElementIndex(descriptor) == CompositeDecoder.DECODE_DONE){"Serialized MetaItem contains additional fields"}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: MetaItem<*>) {
|
||||||
|
encoder.encodeStructure(descriptor) {
|
||||||
|
encodeBooleanElement(descriptor, 0, value is MetaItem.NodeItem)
|
||||||
|
when (value) {
|
||||||
|
is MetaItem.ValueItem -> encodeSerializableElement(descriptor, 1, ValueSerializer, value.value)
|
||||||
|
is MetaItem.NodeItem -> encodeSerializableElement(descriptor, 1, MetaSerializer, value.node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialized for meta
|
* Serialized for meta
|
||||||
*/
|
*/
|
||||||
@Serializer(Meta::class)
|
public object MetaSerializer : KSerializer<Meta> {
|
||||||
object MetaSerializer : KSerializer<Meta> {
|
|
||||||
private val mapSerializer = MapSerializer(
|
private val mapSerializer: KSerializer<Map<NameToken, MetaItem<Meta>>> = MapSerializer(
|
||||||
NameToken.serializer(),
|
NameToken,
|
||||||
MetaItem.serializer(MetaSerializer)
|
MetaItemSerializer//MetaItem.serializer(MetaSerializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
|
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Meta {
|
override fun deserialize(decoder: Decoder): Meta {
|
||||||
return if (decoder is JsonInput) {
|
return if (decoder is JsonDecoder) {
|
||||||
JsonObjectSerializer.deserialize(decoder).toMeta()
|
JsonObject.serializer().deserialize(decoder).toMeta()
|
||||||
} else {
|
} else {
|
||||||
object : MetaBase() {
|
object : MetaBase() {
|
||||||
override val items: Map<NameToken, MetaItem<*>> = mapSerializer.deserialize(decoder)
|
override val items: Map<NameToken, MetaItem<*>> = mapSerializer.deserialize(decoder)
|
||||||
@ -31,8 +71,8 @@ object MetaSerializer : KSerializer<Meta> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: Meta) {
|
override fun serialize(encoder: Encoder, value: Meta) {
|
||||||
if (encoder is JsonOutput) {
|
if (encoder is JsonEncoder) {
|
||||||
JsonObjectSerializer.serialize(encoder, value.toJson())
|
JsonObject.serializer().serialize(encoder, value.toJson())
|
||||||
} else {
|
} else {
|
||||||
mapSerializer.serialize(encoder, value.items)
|
mapSerializer.serialize(encoder, value.items)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
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)
|
@ -5,163 +5,189 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.values.DoubleArrayValue
|
import hep.dataforge.values.DoubleArrayValue
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import hep.dataforge.values.stringList
|
import hep.dataforge.values.asValue
|
||||||
|
import hep.dataforge.values.doubleArray
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
/* Read-write delegates */
|
/* Read-write delegates */
|
||||||
|
|
||||||
open class MutableItemDelegate(
|
public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem<*>?>
|
||||||
override val owner: MutableItemProvider,
|
|
||||||
key: Name? = null,
|
public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = object : MutableItemDelegate {
|
||||||
default: MetaItem<*>? = null
|
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
|
||||||
) : ItemDelegate(owner, key, default), ReadWriteProperty<Any?, MetaItem<*>?> {
|
return getItem(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()
|
val name = key ?: property.name.asName()
|
||||||
owner.setItem(name, value)
|
setItem(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate =
|
/* Mutable converters */
|
||||||
MutableItemDelegate(this, key)
|
|
||||||
|
|
||||||
//Read-write delegates
|
/**
|
||||||
|
* A type converter for a mutable [MetaItem] delegate
|
||||||
|
*/
|
||||||
|
public fun <R : Any> MutableItemDelegate.convert(
|
||||||
|
converter: MetaConverter<R>,
|
||||||
|
): ReadWriteProperty<Any?, R?> = object : ReadWriteProperty<Any?, R?> {
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): R? =
|
||||||
|
this@convert.getValue(thisRef, property)?.let(converter::itemToObject)
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: R?) {
|
||||||
|
val item = value?.let(converter::objectToMetaItem)
|
||||||
|
this@convert.setValue(thisRef, property, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <R : Any> MutableItemDelegate.convert(
|
||||||
|
converter: MetaConverter<R>,
|
||||||
|
default: () -> R,
|
||||||
|
): ReadWriteProperty<Any?, R> = object : ReadWriteProperty<Any?, R> {
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): R =
|
||||||
|
this@convert.getValue(thisRef, property)?.let(converter::itemToObject) ?: default()
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) {
|
||||||
|
val item = value.let(converter::objectToMetaItem)
|
||||||
|
this@convert.setValue(thisRef, property, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <R> MutableItemDelegate.convert(
|
||||||
|
reader: (MetaItem<*>?) -> R,
|
||||||
|
writer: (R) -> MetaItem<*>?,
|
||||||
|
): ReadWriteProperty<Any?, R> = object : ReadWriteProperty<Any?, R> {
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): R =
|
||||||
|
this@convert.getValue(thisRef, property).let(reader)
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) {
|
||||||
|
val item = value?.let(writer)
|
||||||
|
this@convert.setValue(thisRef, property, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Read-write delegates for [MutableItemProvider] */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A property delegate that uses custom key
|
* A property delegate that uses custom key
|
||||||
*/
|
*/
|
||||||
fun MutableItemProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
public fun MutableItemProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
||||||
item(key).convert(MetaConverter.value)
|
item(key).convert(MetaConverter.value)
|
||||||
|
|
||||||
fun MutableItemProvider.string(key: Name? = null): ReadWriteProperty<Any?, String?> =
|
public fun MutableItemProvider.string(key: Name? = null): ReadWriteProperty<Any?, String?> =
|
||||||
item(key).convert(MetaConverter.string)
|
item(key).convert(MetaConverter.string)
|
||||||
|
|
||||||
fun MutableItemProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
|
public fun MutableItemProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
|
||||||
item(key).convert(MetaConverter.boolean)
|
item(key).convert(MetaConverter.boolean)
|
||||||
|
|
||||||
fun MutableItemProvider.number(key: Name? = null): ReadWriteProperty<Any?, Number?> =
|
public fun MutableItemProvider.number(key: Name? = null): ReadWriteProperty<Any?, Number?> =
|
||||||
item(key).convert(MetaConverter.number)
|
item(key).convert(MetaConverter.number)
|
||||||
|
|
||||||
fun MutableItemProvider.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> =
|
public fun MutableItemProvider.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> =
|
||||||
item(key).convert(MetaConverter.string) { default }
|
item(key).convert(MetaConverter.string) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> =
|
public fun MutableItemProvider.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> =
|
||||||
item(key).convert(MetaConverter.boolean) { default }
|
item(key).convert(MetaConverter.boolean) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> =
|
public fun MutableItemProvider.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> =
|
||||||
item(key).convert(MetaConverter.number) { default }
|
item(key).convert(MetaConverter.number) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.value(key: Name? = null, default: () -> Value): ReadWriteProperty<Any?, Value> =
|
public fun MutableItemProvider.value(key: Name? = null, default: () -> Value): ReadWriteProperty<Any?, Value> =
|
||||||
item(key).convert(MetaConverter.value, default)
|
item(key).convert(MetaConverter.value, default)
|
||||||
|
|
||||||
fun MutableItemProvider.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> =
|
public fun MutableItemProvider.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> =
|
||||||
item(key).convert(MetaConverter.string, default)
|
item(key).convert(MetaConverter.string, default)
|
||||||
|
|
||||||
fun MutableItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> =
|
public fun MutableItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> =
|
||||||
item(key).convert(MetaConverter.boolean, default)
|
item(key).convert(MetaConverter.boolean, default)
|
||||||
|
|
||||||
fun MutableItemProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> =
|
public fun MutableItemProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> =
|
||||||
item(key).convert(MetaConverter.number, default)
|
item(key).convert(MetaConverter.number, default)
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> MutableItemProvider.enum(default: E, key: Name? = null): ReadWriteProperty<Any?, E> =
|
public inline fun <reified E : Enum<E>> MutableItemProvider.enum(
|
||||||
|
default: E,
|
||||||
|
key: Name? = null,
|
||||||
|
): ReadWriteProperty<Any?, E> =
|
||||||
item(key).convert(MetaConverter.enum()) { default }
|
item(key).convert(MetaConverter.enum()) { default }
|
||||||
|
|
||||||
inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null): ReadWriteProperty<Any?, M?> =
|
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 { MetaItem.NodeItem(it) } })
|
||||||
|
|
||||||
|
/* Number delegates */
|
||||||
|
|
||||||
fun <T> MutableItemProvider.item(
|
public fun MutableItemProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> =
|
||||||
default: T? = null,
|
|
||||||
key: Name? = null,
|
|
||||||
writer: (T) -> MetaItem<*>? = { MetaItem.of(it) },
|
|
||||||
reader: (MetaItem<*>?) -> T
|
|
||||||
): ReadWriteProperty<Any?, T> = MutableItemDelegate(
|
|
||||||
this,
|
|
||||||
key,
|
|
||||||
default?.let { MetaItem.of(it) }
|
|
||||||
).convert(reader = reader, writer = writer)
|
|
||||||
|
|
||||||
fun Configurable.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
|
||||||
item(key).convert(MetaConverter.value)
|
|
||||||
|
|
||||||
fun <T> MutableItemProvider.value(
|
|
||||||
default: T? = null,
|
|
||||||
key: Name? = null,
|
|
||||||
writer: (T) -> Value? = { Value.of(it) },
|
|
||||||
reader: (Value?) -> T
|
|
||||||
): ReadWriteProperty<Any?, T> = MutableItemDelegate(
|
|
||||||
this,
|
|
||||||
key,
|
|
||||||
default?.let { MetaItem.of(it) }
|
|
||||||
).convert(
|
|
||||||
reader = { reader(it.value) },
|
|
||||||
writer = { value -> writer(value)?.let { MetaItem.ValueItem(it) } }
|
|
||||||
)
|
|
||||||
|
|
||||||
/* Number delegates*/
|
|
||||||
|
|
||||||
fun MutableItemProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> =
|
|
||||||
item(key).convert(MetaConverter.int)
|
item(key).convert(MetaConverter.int)
|
||||||
|
|
||||||
fun MutableItemProvider.double(key: Name? = null): ReadWriteProperty<Any?, Double?> =
|
public fun MutableItemProvider.double(key: Name? = null): ReadWriteProperty<Any?, Double?> =
|
||||||
item(key).convert(MetaConverter.double)
|
item(key).convert(MetaConverter.double)
|
||||||
|
|
||||||
fun MutableItemProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> =
|
public fun MutableItemProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> =
|
||||||
item(key).convert(MetaConverter.long)
|
item(key).convert(MetaConverter.long)
|
||||||
|
|
||||||
fun MutableItemProvider.float(key: Name? = null): ReadWriteProperty<Any?, Float?> =
|
public fun MutableItemProvider.float(key: Name? = null): ReadWriteProperty<Any?, Float?> =
|
||||||
item(key).convert(MetaConverter.float)
|
item(key).convert(MetaConverter.float)
|
||||||
|
|
||||||
|
|
||||||
/* Safe number delegates*/
|
/* Safe number delegates*/
|
||||||
|
|
||||||
fun MutableItemProvider.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> =
|
public fun MutableItemProvider.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> =
|
||||||
item(key).convert(MetaConverter.int) { default }
|
item(key).convert(MetaConverter.int) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> =
|
public fun MutableItemProvider.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> =
|
||||||
item(key).convert(MetaConverter.double) { default }
|
item(key).convert(MetaConverter.double) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> =
|
public fun MutableItemProvider.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> =
|
||||||
item(key).convert(MetaConverter.long) { default }
|
item(key).convert(MetaConverter.long) { default }
|
||||||
|
|
||||||
fun MutableItemProvider.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> =
|
public fun MutableItemProvider.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> =
|
||||||
item(key).convert(MetaConverter.float) { default }
|
item(key).convert(MetaConverter.float) { default }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* Extra delegates for special cases */
|
||||||
* Extra delegates for special cases
|
|
||||||
*/
|
|
||||||
fun MutableItemProvider.stringList(vararg strings: String, key: Name? = null): ReadWriteProperty<Any?, List<String>> =
|
|
||||||
item(listOf(*strings), key) {
|
|
||||||
it?.value?.stringList ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun MutableItemProvider.stringListOrNull(
|
public fun MutableItemProvider.stringList(
|
||||||
vararg strings: String,
|
vararg default: String,
|
||||||
key: Name? = null
|
key: Name? = null,
|
||||||
): ReadWriteProperty<Any?, List<String>?> =
|
): ReadWriteProperty<Any?, List<String>> = item(key).convert(
|
||||||
item(listOf(*strings), key) {
|
reader = { it?.stringList ?: listOf(*default) },
|
||||||
it?.value?.stringList
|
writer = { it.map { str -> str.asValue() }.asValue().asMetaItem() }
|
||||||
}
|
)
|
||||||
|
|
||||||
fun MutableItemProvider.numberList(vararg numbers: Number, key: Name? = null): ReadWriteProperty<Any?, List<Number>> =
|
public fun MutableItemProvider.stringList(
|
||||||
item(listOf(*numbers), key) { item ->
|
key: Name? = null,
|
||||||
item?.value?.list?.map { it.number } ?: emptyList()
|
): ReadWriteProperty<Any?, List<String>?> = item(key).convert(
|
||||||
}
|
reader = { it?.stringList },
|
||||||
|
writer = { it?.map { str -> str.asValue() }?.asValue()?.asMetaItem() }
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
public fun MutableItemProvider.numberList(
|
||||||
* A special delegate for double arrays
|
vararg default: Number,
|
||||||
*/
|
key: Name? = null,
|
||||||
fun MutableItemProvider.doubleArray(vararg doubles: Double, key: Name? = null): ReadWriteProperty<Any?, DoubleArray> =
|
): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
|
||||||
item(doubleArrayOf(*doubles), key) {
|
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) },
|
||||||
(it.value as? DoubleArrayValue)?.value
|
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
|
||||||
?: it?.value?.list?.map { value -> value.number.toDouble() }?.toDoubleArray()
|
)
|
||||||
?: doubleArrayOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> MutableItemProvider.listValue(
|
/* A special delegate for double arrays */
|
||||||
|
|
||||||
|
|
||||||
|
public fun MutableItemProvider.doubleArray(
|
||||||
|
vararg default: Double,
|
||||||
|
key: Name? = null,
|
||||||
|
): ReadWriteProperty<Any?, DoubleArray> = item(key).convert(
|
||||||
|
reader = { it?.value?.doubleArray ?: doubleArrayOf(*default) },
|
||||||
|
writer = { DoubleArrayValue(it).asMetaItem() }
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun <T> MutableItemProvider.listValue(
|
||||||
key: Name? = null,
|
key: Name? = null,
|
||||||
writer: (T) -> Value = { Value.of(it) },
|
writer: (T) -> Value = { Value.of(it) },
|
||||||
reader: (Value) -> T
|
reader: (Value) -> T,
|
||||||
): ReadWriteProperty<Any?, List<T>?> = item(key).convert(MetaConverter.valueList(writer, reader))
|
): ReadWriteProperty<Any?, List<T>?> = item(key).convert(MetaConverter.valueList(writer, reader))
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package hep.dataforge.meta
|
||||||
|
|
||||||
|
import hep.dataforge.names.*
|
||||||
|
import hep.dataforge.values.Value
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
|
||||||
|
public interface MutableItemProvider : ItemProvider {
|
||||||
|
public fun setItem(name: Name, item: MetaItem<*>?)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun MutableItemProvider.getItem(key: String): MetaItem<*>? = getItem(key.toName())
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setValue(name: Name, value: Value?): Unit =
|
||||||
|
setItem(name, value?.let { MetaItem.ValueItem(value) })
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setNode(name: Name, meta: Meta?): Unit =
|
||||||
|
setItem(name, meta?.let { MetaItem.NodeItem(meta) })
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setItem(key: String, item: MetaItem<*>?): Unit = setItem(key.toName(), item)
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setValue(key: String, value: Value?): Unit =
|
||||||
|
setItem(key, value?.let { MetaItem.ValueItem(value) })
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setNode(key: String, meta: Meta?): Unit =
|
||||||
|
setItem(key, meta?.let { MetaItem.NodeItem(meta) })
|
||||||
|
|
||||||
|
public fun MutableItemProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).convert(
|
||||||
|
reader = { it.node },
|
||||||
|
writer = { it?.let { MetaItem.NodeItem(it) } }
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun MutableItemProvider.remove(name: Name): Unit = setItem(name, null)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun MutableItemProvider.remove(name: String): Unit = remove(name.toName())
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Universal unsafe set method
|
||||||
|
*/
|
||||||
|
public operator fun MutableItemProvider.set(name: Name, value: Any?) {
|
||||||
|
when (value) {
|
||||||
|
null -> remove(name)
|
||||||
|
is MetaItem<*> -> setItem(name, value)
|
||||||
|
is Meta -> setNode(name, value)
|
||||||
|
is Configurable -> setNode(name, value.config)
|
||||||
|
else -> setValue(name, Value.of(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public operator fun MutableItemProvider.set(name: NameToken, value: Any?): Unit =
|
||||||
|
set(name.asName(), value)
|
||||||
|
|
||||||
|
public operator fun MutableItemProvider.set(key: String, value: Any?): Unit =
|
||||||
|
set(key.toName(), value)
|
||||||
|
|
||||||
|
public operator fun MutableItemProvider.set(key: String, index: String, value: Any?): Unit =
|
||||||
|
set(key.toName().withIndex(index), value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Same name siblings generation */
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setIndexedItems(
|
||||||
|
name: Name,
|
||||||
|
items: Iterable<MetaItem<*>>,
|
||||||
|
indexFactory: (MetaItem<*>, index: Int) -> String = { _, index -> index.toString() }
|
||||||
|
) {
|
||||||
|
val tokens = name.tokens.toMutableList()
|
||||||
|
val last = tokens.last()
|
||||||
|
items.forEachIndexed { index, meta ->
|
||||||
|
val indexedToken = NameToken(last.body, last.index + indexFactory(meta, index))
|
||||||
|
tokens[tokens.lastIndex] = indexedToken
|
||||||
|
setItem(Name(tokens), meta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun MutableItemProvider.setIndexed(
|
||||||
|
name: Name,
|
||||||
|
metas: Iterable<Meta>,
|
||||||
|
indexFactory: (Meta, index: Int) -> String = { _, index -> index.toString() }
|
||||||
|
) {
|
||||||
|
setIndexedItems(name, metas.map { MetaItem.NodeItem(it) }) { item, index -> indexFactory(item.node!!, index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public operator fun MutableItemProvider.set(name: Name, metas: Iterable<Meta>): Unit = setIndexed(name, metas)
|
||||||
|
public operator fun MutableItemProvider.set(name: String, metas: Iterable<Meta>): Unit = setIndexed(name.toName(), metas)
|
@ -1,13 +1,8 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.values.Value
|
|
||||||
|
|
||||||
interface MutableItemProvider : ItemProvider {
|
public interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider {
|
||||||
fun setItem(name: Name, item: MetaItem<*>?)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider {
|
|
||||||
override val items: Map<NameToken, MetaItem<M>>
|
override val items: Map<NameToken, MetaItem<M>>
|
||||||
// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
||||||
// fun removeListener(owner: Any? = null)
|
// fun removeListener(owner: Any? = null)
|
||||||
@ -18,19 +13,19 @@ interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider
|
|||||||
*
|
*
|
||||||
* Changes in Meta are not thread safe.
|
* Changes in Meta are not thread safe.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
|
public abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
|
||||||
protected val _items: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap()
|
protected val children: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap()
|
||||||
|
|
||||||
override val items: Map<NameToken, MetaItem<M>>
|
override val items: Map<NameToken, MetaItem<M>>
|
||||||
get() = _items
|
get() = children
|
||||||
|
|
||||||
//protected abstract fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?)
|
//protected abstract fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?)
|
||||||
|
|
||||||
protected open fun replaceItem(key: NameToken, oldItem: MetaItem<M>?, newItem: MetaItem<M>?) {
|
protected open fun replaceItem(key: NameToken, oldItem: MetaItem<M>?, newItem: MetaItem<M>?) {
|
||||||
if (newItem == null) {
|
if (newItem == null) {
|
||||||
_items.remove(key)
|
children.remove(key)
|
||||||
} else {
|
} else {
|
||||||
_items[key] = newItem
|
children[key] = newItem
|
||||||
}
|
}
|
||||||
//itemChanged(key.asName(), oldItem, newItem)
|
//itemChanged(key.asName(), oldItem, newItem)
|
||||||
}
|
}
|
||||||
@ -56,12 +51,12 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
|
|||||||
when (name.length) {
|
when (name.length) {
|
||||||
0 -> error("Can't setValue meta item for empty name")
|
0 -> error("Can't setValue meta item for empty name")
|
||||||
1 -> {
|
1 -> {
|
||||||
val token = name.first()!!
|
val token = name.firstOrNull()!!
|
||||||
@Suppress("UNCHECKED_CAST") val oldItem: MetaItem<M>? = get(name) as? MetaItem<M>
|
@Suppress("UNCHECKED_CAST") val oldItem: MetaItem<M>? = get(name) as? MetaItem<M>
|
||||||
replaceItem(token, oldItem, wrapItem(item))
|
replaceItem(token, oldItem, wrapItem(item))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val token = name.first()!!
|
val token = name.firstOrNull()!!
|
||||||
//get existing or create new node. Query is ignored for new node
|
//get existing or create new node. Query is ignored for new node
|
||||||
if (items[token] == null) {
|
if (items[token] == null) {
|
||||||
replaceItem(token, null, MetaItem.NodeItem(empty()))
|
replaceItem(token, null, MetaItem.NodeItem(empty()))
|
||||||
@ -72,52 +67,13 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
inline fun MutableMeta<*>.remove(name: Name) = setItem(name, null)
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
inline fun MutableMeta<*>.remove(name: String) = remove(name.toName())
|
|
||||||
|
|
||||||
operator fun MutableMeta<*>.set(name: Name, item: MetaItem<*>?) = setItem(name, item)
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setValue(name: Name, value: Value) = setItem(name, MetaItem.ValueItem(value))
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value)
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setItem(name: String, item: MetaItem<*>?) = setItem(name.toName(), item)
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setNode(name: Name, node: Meta) =
|
|
||||||
setItem(name, MetaItem.NodeItem(node))
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Universal unsafe set method
|
|
||||||
*/
|
|
||||||
operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
|
||||||
when (value) {
|
|
||||||
null -> remove(name)
|
|
||||||
is MetaItem<*> -> setItem(name, value)
|
|
||||||
is Meta -> setNode(name, value)
|
|
||||||
is Configurable -> setNode(name, value.config)
|
|
||||||
else -> setValue(name, Value.of(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun MutableMeta<*>.set(name: NameToken, value: Any?) = set(name.asName(), value)
|
|
||||||
|
|
||||||
operator fun MutableMeta<*>.set(key: String, value: Any?) = set(key.toName(), value)
|
|
||||||
|
|
||||||
operator fun MutableMeta<*>.set(key: String, index: String, value: Any?) = set(key.toName().withIndex(index), value)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing mutable node with another node. The rules are following:
|
* Update existing mutable node with another node. The rules are following:
|
||||||
* * value replaces anything
|
* * value replaces anything
|
||||||
* * node updates node and replaces anything but node
|
* * node updates node and replaces anything but node
|
||||||
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
|
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
|
||||||
*/
|
*/
|
||||||
fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
public fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
||||||
meta.items.forEach { entry ->
|
meta.items.forEach { entry ->
|
||||||
when (val value = entry.value) {
|
when (val value = entry.value) {
|
||||||
is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value)
|
is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value)
|
||||||
@ -127,54 +83,27 @@ fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same name siblings generation */
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setIndexedItems(
|
|
||||||
name: Name,
|
|
||||||
items: Iterable<MetaItem<*>>,
|
|
||||||
indexFactory: (MetaItem<*>, index: Int) -> String = { _, index -> index.toString() }
|
|
||||||
) {
|
|
||||||
val tokens = name.tokens.toMutableList()
|
|
||||||
val last = tokens.last()
|
|
||||||
items.forEachIndexed { index, meta ->
|
|
||||||
val indexedToken = NameToken(last.body, last.index + indexFactory(meta, index))
|
|
||||||
tokens[tokens.lastIndex] = indexedToken
|
|
||||||
setItem(Name(tokens), meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setIndexed(
|
|
||||||
name: Name,
|
|
||||||
metas: Iterable<Meta>,
|
|
||||||
indexFactory: (Meta, index: Int) -> String = { _, index -> index.toString() }
|
|
||||||
) {
|
|
||||||
setIndexedItems(name, metas.map { MetaItem.NodeItem(it) }) { item, index -> indexFactory(item.node!!, index) }
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun MutableMeta<*>.set(name: Name, metas: Iterable<Meta>): Unit = setIndexed(name, metas)
|
|
||||||
operator fun MutableMeta<*>.set(name: String, metas: Iterable<Meta>): Unit = setIndexed(name.toName(), metas)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the node with a same-name-sibling, automatically generating numerical index
|
* Append the node with a same-name-sibling, automatically generating numerical index
|
||||||
*/
|
*/
|
||||||
fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
public fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
||||||
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
||||||
val newIndex = name.last()!!.index
|
val newIndex = name.lastOrNull()!!.index
|
||||||
if (newIndex.isNotEmpty()) {
|
if (newIndex != null) {
|
||||||
set(name, value)
|
set(name, value)
|
||||||
} else {
|
} else {
|
||||||
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1
|
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.maxOrNull() ?: -1) + 1
|
||||||
set(name.withIndex(index.toString()), value)
|
set(name.withIndex(index.toString()), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)
|
public fun <M : MutableMeta<M>> M.append(name: String, value: Any?): Unit = append(name.toName(), value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply existing node with given [builder] or create a new element with it.
|
* Apply existing node with given [builder] or create a new element with it.
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
fun <M : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) {
|
public fun <M : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) {
|
||||||
val item = when (val existingItem = get(name)) {
|
val item = when (val existingItem = get(name)) {
|
||||||
null -> empty().also { set(name, it) }
|
null -> empty().also { set(name, it) }
|
||||||
is MetaItem.NodeItem<M> -> existingItem.node
|
is MetaItem.NodeItem<M> -> existingItem.node
|
||||||
|
@ -3,28 +3,54 @@ package hep.dataforge.meta
|
|||||||
import hep.dataforge.meta.descriptors.*
|
import hep.dataforge.meta.descriptors.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.asName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification].
|
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification].
|
||||||
|
* Default item provider and [NodeDescriptor] are optional
|
||||||
*/
|
*/
|
||||||
open class Scheme() : Configurable, Described, MetaRepr {
|
public open class Scheme(
|
||||||
constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() {
|
config: Config = Config(),
|
||||||
this.config = config
|
internal var default: ItemProvider? = null,
|
||||||
this.defaultProvider = defaultProvider
|
descriptor: NodeDescriptor? = null,
|
||||||
|
) : Configurable, MutableItemProvider, Described, MetaRepr {
|
||||||
|
|
||||||
|
override var config: Config = config
|
||||||
|
internal set(value) {
|
||||||
|
//Fix problem with `init` blocks in specifications
|
||||||
|
field = value.apply { update(field) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override var descriptor: NodeDescriptor? = descriptor
|
||||||
|
internal set
|
||||||
|
|
||||||
|
|
||||||
|
public fun getDefaultItem(name: Name): MetaItem<*>? {
|
||||||
|
return default?.getItem(name) ?: descriptor?.get(name)?.defaultItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
//constructor(config: Config, default: Meta) : this(config, { default[it] })
|
/**
|
||||||
constructor(config: Config) : this(config, { null })
|
* Get a property with default
|
||||||
|
*/
|
||||||
|
override fun getItem(name: Name): MetaItem<*>? = config[name] ?: getDefaultItem(name)
|
||||||
|
|
||||||
final override var config: Config = Config()
|
/**
|
||||||
internal set
|
* Check if property with given [name] could be assigned to [item]
|
||||||
|
*/
|
||||||
|
public fun validateItem(name: Name, item: MetaItem<*>?): Boolean {
|
||||||
|
val descriptor = descriptor?.get(name)
|
||||||
|
return descriptor?.validateItem(item) ?: true
|
||||||
|
}
|
||||||
|
|
||||||
var defaultProvider: (Name) -> MetaItem<*>? = { null }
|
/**
|
||||||
internal set
|
* Set a configurable property
|
||||||
|
*/
|
||||||
override fun getDefaultItem(name: Name): MetaItem<*>? {
|
override fun setItem(name: Name, item: MetaItem<*>?) {
|
||||||
return defaultProvider(name) ?: descriptor?.get(name)?.defaultItem()
|
if (validateItem(name, item)) {
|
||||||
|
config.setItem(name, item)
|
||||||
|
} else {
|
||||||
|
error("Validation failed for property $name with value $item")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,56 +58,73 @@ open class Scheme() : Configurable, Described, MetaRepr {
|
|||||||
* values if default value is unavailable.
|
* values if default value is unavailable.
|
||||||
* Values from [defaultProvider] completely replace
|
* Values from [defaultProvider] completely replace
|
||||||
*/
|
*/
|
||||||
open val defaultLayer: Meta get() = DefaultLayer(Name.EMPTY)
|
public open val defaultLayer: Meta
|
||||||
|
get() = object : MetaBase() {
|
||||||
|
override val items: Map<NameToken, MetaItem<*>> = buildMap {
|
||||||
|
descriptor?.items?.forEach { (key, itemDescriptor) ->
|
||||||
|
val token = NameToken(key)
|
||||||
|
val name = token.asName()
|
||||||
|
val item = default?.getItem(name) ?: itemDescriptor.defaultItem()
|
||||||
|
if (item != null) {
|
||||||
|
put(token, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun toMeta(): Laminate = Laminate(config, defaultLayer)
|
override fun toMeta(): Laminate = Laminate(config, defaultLayer)
|
||||||
|
|
||||||
private inner class DefaultLayer(val path: Name) : MetaBase() {
|
public fun isEmpty(): Boolean = config.isEmpty()
|
||||||
override val items: Map<NameToken, MetaItem<*>> =
|
|
||||||
(descriptor?.get(path) as? NodeDescriptor)?.items?.entries?.associate { (key, descriptor) ->
|
|
||||||
val token = NameToken(key)
|
|
||||||
val fullName = path + token
|
|
||||||
val item: MetaItem<*> = when (descriptor) {
|
|
||||||
is ValueDescriptor -> getDefaultItem(fullName) ?: descriptor.defaultItem()
|
|
||||||
is NodeDescriptor -> MetaItem.NodeItem(DefaultLayer(fullName))
|
|
||||||
}
|
|
||||||
token to item
|
|
||||||
} ?: emptyMap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline operator fun <T : Scheme> T.invoke(block: T.() -> Unit) = apply(block)
|
/**
|
||||||
|
* A shortcut to edit a [Scheme] object in-place
|
||||||
|
*/
|
||||||
|
public inline operator fun <T : Scheme> T.invoke(block: T.() -> Unit): T = apply(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specification for simplified generation of wrappers
|
* A specification for simplified generation of wrappers
|
||||||
*/
|
*/
|
||||||
open class SchemeSpec<T : Scheme>(val builder: () -> T) :
|
public open class SchemeSpec<T : Scheme>(
|
||||||
Specification<T> {
|
private val builder: (config: Config, defaultProvider: ItemProvider, descriptor: NodeDescriptor?) -> T,
|
||||||
override fun empty(): T = builder()
|
) : Specification<T>, Described {
|
||||||
|
|
||||||
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T {
|
public constructor(emptyBuilder: () -> T) : this({ config: Config, defaultProvider: ItemProvider, descriptor: NodeDescriptor? ->
|
||||||
return empty().apply {
|
emptyBuilder().apply {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.defaultProvider = defaultProvider
|
this.default = defaultProvider
|
||||||
|
this.descriptor = descriptor
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
override fun read(meta: Meta, defaultProvider: ItemProvider): T =
|
||||||
|
builder(Config(), meta.withDefault(defaultProvider), descriptor)
|
||||||
|
|
||||||
|
override fun wrap(config: Config, defaultProvider: ItemProvider): T {
|
||||||
|
return builder(config, defaultProvider, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Generate descriptor from Scheme class
|
||||||
|
override val descriptor: NodeDescriptor? get() = null
|
||||||
|
|
||||||
@Suppress("OVERRIDE_BY_INLINE")
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
final override inline operator fun invoke(action: T.() -> Unit) = empty().apply(action)
|
final override inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
///**
|
||||||
* A scheme that uses [Meta] as a default layer
|
// * A scheme that uses [Meta] as a default layer
|
||||||
*/
|
// */
|
||||||
open class MetaScheme(
|
//public open class MetaScheme(
|
||||||
val meta: Meta,
|
// private val meta: Meta,
|
||||||
override val descriptor: NodeDescriptor? = null,
|
// override val descriptor: NodeDescriptor? = null,
|
||||||
config: Config = Config()
|
// config: Config = Config(),
|
||||||
) : Scheme(config, meta::get) {
|
//) : Scheme(config, meta) {
|
||||||
override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
|
// override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
|
||||||
|
//}
|
||||||
|
|
||||||
|
public fun Meta.asScheme(): Scheme = Scheme().apply {
|
||||||
|
config = this@asScheme.asConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.asScheme() =
|
public fun <T : MutableItemProvider> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit = {}): T =
|
||||||
MetaScheme(this)
|
spec.read(this).apply(block)
|
||||||
|
|
||||||
fun <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit) = spec.wrap(this).apply(block)
|
|
||||||
|
@ -1,67 +1,102 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.asName
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to apply custom configuration in a type safe way to simple untyped configuration.
|
* Allows to apply custom configuration in a type safe way to simple untyped configuration.
|
||||||
* By convention [Scheme] companion should inherit this class
|
* By convention [Scheme] companion should inherit this class
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
interface Specification<T : Configurable> {
|
public interface Specification<T : MutableItemProvider> {
|
||||||
fun empty() = wrap()
|
/**
|
||||||
|
* Read generic read-only meta with this [Specification] producing instance of desired type.
|
||||||
|
*/
|
||||||
|
public fun read(meta: Meta, defaultProvider: ItemProvider = ItemProvider.EMPTY): T
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap generic configuration producing instance of desired type
|
* Wrap mutable [Config], using it as inner storage (changes to [Specification] are reflected on [Config]
|
||||||
*/
|
*/
|
||||||
fun wrap(config: Config = Config(), defaultProvider: (Name) -> MetaItem<*>? = { null }): T
|
public fun wrap(config: Config, defaultProvider: ItemProvider = ItemProvider.EMPTY): T =
|
||||||
|
read(config as Meta, defaultProvider)
|
||||||
|
|
||||||
operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
|
/**
|
||||||
|
* Generate an empty object
|
||||||
|
*/
|
||||||
|
public fun empty(): T = read(Meta.EMPTY)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method to use specifications in builders
|
||||||
|
*/
|
||||||
|
public operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update given configuration using given type as a builder
|
* Update given configuration using given type as a builder
|
||||||
*/
|
*/
|
||||||
fun <T : Configurable> Specification<T>.update(config: Config, action: T.() -> Unit): T = wrap(config).apply(action)
|
public fun <T : MutableItemProvider> Specification<T>.update(meta: Meta, action: T.() -> Unit): T =
|
||||||
|
read(meta).apply(action)
|
||||||
/**
|
|
||||||
* Wrap a configuration using static meta as default
|
|
||||||
*/
|
|
||||||
fun <T : Configurable> Specification<T>.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T =
|
|
||||||
wrap(config) { default[it] }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap a configuration using static meta as default
|
|
||||||
*/
|
|
||||||
fun <T : Configurable> Specification<T>.wrap(source: Meta): T {
|
|
||||||
val default = source.seal()
|
|
||||||
return wrap(source.asConfig(), default)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply specified configuration to configurable
|
* Apply specified configuration to configurable
|
||||||
*/
|
*/
|
||||||
fun <T : Configurable, C : Configurable, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit) =
|
public fun <T : MetaRepr, C : MutableItemProvider, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit): T =
|
||||||
apply { spec.update(config, action) }
|
apply { spec.update(toMeta(), action) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update configuration using given specification
|
* Update configuration using given specification
|
||||||
*/
|
*/
|
||||||
fun <C : Configurable, S : Specification<C>> Configurable.update(spec: S, action: C.() -> Unit) =
|
public fun <C : MutableItemProvider, S : Specification<C>> Configurable.update(
|
||||||
|
spec: S,
|
||||||
|
action: C.() -> Unit,
|
||||||
|
): Configurable =
|
||||||
apply { spec.update(config, action) }
|
apply { spec.update(config, action) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a style based on given specification
|
* Create a style based on given specification
|
||||||
*/
|
*/
|
||||||
fun <C : Configurable, S : Specification<C>> S.createStyle(action: C.() -> Unit): Meta =
|
public fun <C : MutableItemProvider, S : Specification<C>> S.createStyle(action: C.() -> Unit): Meta =
|
||||||
Config().also { update(it, action) }
|
Config().also { update(it, action) }
|
||||||
|
|
||||||
fun <T : Configurable> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let {
|
public fun <T : MutableItemProvider> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let {
|
||||||
spec.wrap(
|
spec.wrap(
|
||||||
Config(), it
|
Config(), it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("configSpec")
|
@JvmName("configSpec")
|
||||||
fun <T : Configurable> MetaItem<Config>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(it) }
|
public fun <T : MutableItemProvider> MetaItem<Config>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(it) }
|
||||||
|
|
||||||
|
public fun <T : Scheme> MutableItemProvider.spec(
|
||||||
|
spec: Specification<T>, key: Name? = null,
|
||||||
|
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
|
||||||
|
val name = key ?: property.name.asName()
|
||||||
|
return getItem(name).node?.let { spec.read(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||||
|
val name = key ?: property.name.asName()
|
||||||
|
setItem(name, value?.toMeta()?.asMetaItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T : Scheme> MutableItemProvider.spec(
|
||||||
|
spec: Specification<T>,
|
||||||
|
default: T,
|
||||||
|
key: Name? = null,
|
||||||
|
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
|
val name = key ?: property.name.asName()
|
||||||
|
return getItem(name).node?.let { spec.read(it) } ?: default
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
|
val name = key ?: property.name.asName()
|
||||||
|
setItem(name, value.toMeta().asMetaItem())
|
||||||
|
}
|
||||||
|
}
|
@ -4,8 +4,8 @@ package hep.dataforge.meta
|
|||||||
* General marker for dataforge builders
|
* General marker for dataforge builders
|
||||||
*/
|
*/
|
||||||
@DslMarker
|
@DslMarker
|
||||||
annotation class DFBuilder
|
public annotation class DFBuilder
|
||||||
|
|
||||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class DFExperimental
|
public annotation class DFExperimental
|
@ -3,11 +3,11 @@ package hep.dataforge.meta.descriptors
|
|||||||
/**
|
/**
|
||||||
* An object which provides its descriptor
|
* An object which provides its descriptor
|
||||||
*/
|
*/
|
||||||
interface Described {
|
public interface Described {
|
||||||
val descriptor: ItemDescriptor?
|
public val descriptor: ItemDescriptor?
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
const val DESCRIPTOR_NODE = "@descriptor"
|
//public const val DESCRIPTOR_NODE: String = "@descriptor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +1,48 @@
|
|||||||
package hep.dataforge.meta.descriptors
|
package hep.dataforge.meta.descriptors
|
||||||
|
|
||||||
import hep.dataforge.meta.Laminate
|
import hep.dataforge.meta.Laminate
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaBase
|
import hep.dataforge.meta.MetaBase
|
||||||
import hep.dataforge.meta.MetaItem
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.values.Null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [Meta] that wraps a descriptor node
|
* A [Meta] that is constructed from [NodeDescriptor]
|
||||||
*/
|
*/
|
||||||
class DescriptorMeta(val descriptor: NodeDescriptor) : MetaBase() {
|
private class DescriptorMeta(val descriptor: NodeDescriptor) : Meta, MetaBase() {
|
||||||
override val items: Map<NameToken, MetaItem<*>>
|
override val items: Map<NameToken, MetaItem<*>>
|
||||||
get() = descriptor.items.entries.associate { entry ->
|
get() = buildMap {
|
||||||
NameToken(entry.key) to entry.value.defaultItem()
|
descriptor.items.forEach { (token, descriptorItem) ->
|
||||||
|
val item = descriptorItem.defaultItem()
|
||||||
|
if (item != null) {
|
||||||
|
put(NameToken(token), item)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NodeDescriptor.buildDefaultMeta() = Laminate(default, DescriptorMeta(this))
|
/**
|
||||||
|
* Generate a laminate representing default item set generated by this descriptor
|
||||||
|
*/
|
||||||
|
public fun NodeDescriptor.defaultMeta(): Laminate = Laminate(default, DescriptorMeta(this))
|
||||||
|
|
||||||
fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> =
|
/**
|
||||||
MetaItem.NodeItem(buildDefaultMeta())
|
* Build a default [MetaItem.NodeItem] from this node descriptor
|
||||||
|
*/
|
||||||
|
internal fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> =
|
||||||
|
MetaItem.NodeItem(defaultMeta())
|
||||||
|
|
||||||
fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null)
|
/**
|
||||||
|
* Build a default [MetaItem.ValueItem] from this descriptor
|
||||||
|
*/
|
||||||
|
internal fun ValueDescriptor.defaultItem(): MetaItem.ValueItem? {
|
||||||
|
return MetaItem.ValueItem(default ?: return null)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a default [MetaItem] from descriptor.
|
* Build a default [MetaItem] from descriptor.
|
||||||
*/
|
*/
|
||||||
fun ItemDescriptor.defaultItem(): MetaItem<*> {
|
public fun ItemDescriptor.defaultItem(): MetaItem<*>? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ValueDescriptor -> defaultItem()
|
is ValueDescriptor -> defaultItem()
|
||||||
is NodeDescriptor -> defaultItem()
|
is NodeDescriptor -> defaultItem()
|
||||||
|
@ -4,29 +4,26 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.values.*
|
import hep.dataforge.values.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common parent for [ValueDescriptor] and [NodeDescriptor]. Describes a single [MetaItem] or a group of same-name-siblings.
|
||||||
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
sealed class ItemDescriptor(val config: Config) {
|
public sealed class ItemDescriptor(public val config: Config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if same name siblings with this name are allowed
|
* True if same name siblings with this name are allowed
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
var multiple: Boolean by config.boolean(false)
|
public var multiple: Boolean by config.boolean(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The item description
|
* The item description text
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
var info: String? by config.string()
|
public var info: String? by config.string()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the item is required
|
* True if the item is required
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
abstract var required: Boolean
|
public abstract var required: Boolean
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,29 +31,29 @@ sealed class ItemDescriptor(val config: Config) {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var attributes by config.node()
|
public var attributes: Config? by config.node()
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure attributes of the descriptor
|
* An index field by which this node is identified in case of same name siblings construct
|
||||||
*/
|
*/
|
||||||
fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
public var indexKey: String by config.string(DEFAULT_INDEX_KEY)
|
||||||
(attributes ?: Config().also { this.attributes = it }).apply(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public companion object{
|
||||||
* Set specific attribute in the descriptor
|
public const val DEFAULT_INDEX_KEY: String = "@index"
|
||||||
*/
|
|
||||||
fun ItemDescriptor.setAttribute(name: Name, value: Any?) {
|
|
||||||
attributes {
|
|
||||||
set(name, value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure attributes of the descriptor, creating an attributes node if needed.
|
||||||
|
*/
|
||||||
|
public fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
||||||
|
(attributes ?: Config().also { this.attributes = it }).apply(block)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if given item suits the descriptor
|
* Check if given item suits the descriptor
|
||||||
*/
|
*/
|
||||||
fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
public fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
||||||
if (item == null) return !required
|
if (item == null) return !required
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ValueDescriptor -> isAllowedValue(item.value ?: return false)
|
is ValueDescriptor -> isAllowedValue(item.value ?: return false)
|
||||||
@ -73,7 +70,7 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
public class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||||
init {
|
init {
|
||||||
config[IS_NODE_KEY] = true
|
config[IS_NODE_KEY] = true
|
||||||
}
|
}
|
||||||
@ -90,14 +87,12 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var default by config.node()
|
public var default: Config? by config.node()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An index field by which this node is identified in case of same name siblings construct
|
* The map of children item descriptors (both nodes and values)
|
||||||
*/
|
*/
|
||||||
var indexKey by config.string(DEFAULT_INDEX_KEY)
|
public val items: Map<String, ItemDescriptor>
|
||||||
|
|
||||||
val items: Map<String, ItemDescriptor>
|
|
||||||
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
||||||
val node = item.node ?: error("Node descriptor must be a node")
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
if (node[IS_NODE_KEY].boolean == true) {
|
if (node[IS_NODE_KEY].boolean == true) {
|
||||||
@ -111,7 +106,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
* The map of children node descriptors
|
* The map of children node descriptors
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val nodes: Map<String, NodeDescriptor>
|
public val nodes: Map<String, NodeDescriptor>
|
||||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||||
it.value.node[IS_NODE_KEY].boolean == true
|
it.value.node[IS_NODE_KEY].boolean == true
|
||||||
}.associate { (name, item) ->
|
}.associate { (name, item) ->
|
||||||
@ -120,9 +115,9 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of value descriptors
|
* The list of children value descriptors
|
||||||
*/
|
*/
|
||||||
val values: Map<String, ValueDescriptor>
|
public val values: Map<String, ValueDescriptor>
|
||||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||||
it.value.node[IS_NODE_KEY].boolean != true
|
it.value.node[IS_NODE_KEY].boolean != true
|
||||||
}.associate { (name, item) ->
|
}.associate { (name, item) ->
|
||||||
@ -141,7 +136,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
}
|
}
|
||||||
NodeDescriptor(config)
|
NodeDescriptor(config)
|
||||||
}
|
}
|
||||||
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
|
else -> buildNode(name.firstOrNull()?.asName()!!).buildNode(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,39 +149,43 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
config[token] = descriptor.config
|
config[token] = descriptor.config
|
||||||
}
|
}
|
||||||
|
|
||||||
fun item(name: Name, descriptor: ItemDescriptor) {
|
public fun item(name: Name, descriptor: ItemDescriptor) {
|
||||||
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
|
buildNode(name.cutLast()).newItem(name.lastOrNull().toString(), descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun item(name: String, descriptor: ItemDescriptor) {
|
public fun item(name: String, descriptor: ItemDescriptor) {
|
||||||
item(name.toName(), descriptor)
|
item(name.toName(), descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun node(name: Name, block: NodeDescriptor.() -> Unit) {
|
/**
|
||||||
|
* Create and configure a child node descriptor
|
||||||
|
*/
|
||||||
|
public fun node(name: Name, block: NodeDescriptor.() -> Unit) {
|
||||||
item(name, NodeDescriptor().apply(block))
|
item(name, NodeDescriptor().apply(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
public fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
||||||
node(name.toName(), block)
|
node(name.toName(), block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun value(name: Name, block: ValueDescriptor.() -> Unit) {
|
/**
|
||||||
|
* Create and configure child value descriptor
|
||||||
|
*/
|
||||||
|
public fun value(name: Name, block: ValueDescriptor.() -> Unit) {
|
||||||
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
||||||
item(name, ValueDescriptor().apply(block))
|
item(name, ValueDescriptor().apply(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
public fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
||||||
value(name.toName(), block)
|
value(name.toName(), block)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
public companion object {
|
||||||
|
|
||||||
val ITEM_KEY = "item".asName()
|
internal val ITEM_KEY: Name = "item".asName()
|
||||||
val IS_NODE_KEY = "@isNode".asName()
|
internal val IS_NODE_KEY: Name = "@isNode".asName()
|
||||||
|
|
||||||
const val DEFAULT_INDEX_KEY = "@index"
|
public inline operator fun invoke(block: NodeDescriptor.() -> Unit): NodeDescriptor = NodeDescriptor().apply(block)
|
||||||
|
|
||||||
inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block)
|
|
||||||
|
|
||||||
//TODO infer descriptor from spec
|
//TODO infer descriptor from spec
|
||||||
}
|
}
|
||||||
@ -195,15 +194,15 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
/**
|
/**
|
||||||
* Get a descriptor item associated with given name or null if item for given name not provided
|
* Get a descriptor item associated with given name or null if item for given name not provided
|
||||||
*/
|
*/
|
||||||
operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
public operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
||||||
if (name.isEmpty()) return this
|
if (name.isEmpty()) return this
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ValueDescriptor -> null // empty name already checked
|
is ValueDescriptor -> null // empty name already checked
|
||||||
is NodeDescriptor -> items[name.first()!!.toString()]?.get(name.cutFirst())
|
is NodeDescriptor -> items[name.firstOrNull()!!.toString()]?.get(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
|
public operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A descriptor for meta value
|
* A descriptor for meta value
|
||||||
@ -213,7 +212,7 @@ operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
public class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the value is required
|
* True if the value is required
|
||||||
@ -227,9 +226,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var default: Value? by config.value()
|
public var default: Value? by config.value()
|
||||||
|
|
||||||
fun default(v: Any) {
|
public fun default(v: Any) {
|
||||||
this.default = Value.of(v)
|
this.default = Value.of(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,9 +237,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var type: List<ValueType>? by config.listValue { ValueType.valueOf(it.string) }
|
public var type: List<ValueType>? by config.listValue { ValueType.valueOf(it.string) }
|
||||||
|
|
||||||
fun type(vararg t: ValueType) {
|
public fun type(vararg t: ValueType) {
|
||||||
this.type = listOf(*t)
|
this.type = listOf(*t)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +250,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun isAllowedValue(value: Value): Boolean {
|
public fun isAllowedValue(value: Value): Boolean {
|
||||||
return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
||||||
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
||||||
}
|
}
|
||||||
@ -262,7 +261,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var allowedValues: List<Value> by config.item().convert(
|
public var allowedValues: List<Value> by config.item().convert(
|
||||||
reader = {
|
reader = {
|
||||||
val value = it.value
|
val value = it.value
|
||||||
when {
|
when {
|
||||||
@ -279,7 +278,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
/**
|
/**
|
||||||
* Allow given list of value and forbid others
|
* Allow given list of value and forbid others
|
||||||
*/
|
*/
|
||||||
fun allow(vararg v: Any) {
|
public fun allow(vararg v: Any) {
|
||||||
this.allowedValues = v.map { Value.of(it) }
|
this.allowedValues = v.map { Value.of(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +286,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
|||||||
/**
|
/**
|
||||||
* Merge two node descriptors into one using first one as primary
|
* Merge two node descriptors into one using first one as primary
|
||||||
*/
|
*/
|
||||||
operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
|
public operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
|
||||||
return NodeDescriptor().apply {
|
return NodeDescriptor().apply {
|
||||||
config.update(other.config)
|
config.update(other.config)
|
||||||
config.update(this@plus.config)
|
config.update(this@plus.config)
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package hep.dataforge.meta
|
||||||
|
|
||||||
|
import hep.dataforge.names.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Meta.getIndexed(name: Name): Map<String?, MetaItem<*>> {
|
||||||
|
val root = when (name.length) {
|
||||||
|
0 -> error("Can't use empty name for 'getIndexed'")
|
||||||
|
1 -> this
|
||||||
|
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 Meta.getIndexed(name: String): Map<String?, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all items matching given name.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> =
|
||||||
|
(this as Meta).getIndexed(name) as Map<String, MetaItem<M>>
|
||||||
|
|
||||||
|
public fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> =
|
||||||
|
getIndexed(name.toName())
|
@ -8,7 +8,7 @@ import hep.dataforge.values.Value
|
|||||||
/**
|
/**
|
||||||
* Convert meta to map of maps
|
* Convert meta to map of maps
|
||||||
*/
|
*/
|
||||||
fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
|
public fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
|
||||||
return items.entries.associate { (token, item) ->
|
return items.entries.associate { (token, item) ->
|
||||||
token.toString() to when (item) {
|
token.toString() to when (item) {
|
||||||
is MetaItem.NodeItem -> item.node.toMap()
|
is MetaItem.NodeItem -> item.node.toMap()
|
||||||
@ -22,7 +22,7 @@ fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
|
|||||||
* All other values will be converted to values.
|
* All other values will be converted to values.
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
fun Map<String, Any?>.toMeta(descriptor: NodeDescriptor? = null): Meta = Meta {
|
public fun Map<String, Any?>.toMeta(descriptor: NodeDescriptor? = null): Meta = Meta {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun toItem(value: Any?): MetaItem<*> = when (value) {
|
fun toItem(value: Any?): MetaItem<*> = when (value) {
|
||||||
is MetaItem<*> -> value
|
is MetaItem<*> -> value
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user