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/
|
||||
|
||||
|
||||
!gradle-wrapper.jar
|
||||
gradle.properties
|
||||
!gradle-wrapper.jar
|
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 {
|
||||
val toolsVersion = "0.5.0"
|
||||
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"
|
||||
id("ru.mipt.npm.project")
|
||||
}
|
||||
|
||||
val dataforgeVersion by extra("0.1.8")
|
||||
val dataforgeVersion by extra("0.2.0")
|
||||
|
||||
val bintrayRepo by extra("dataforge")
|
||||
val githubProject by extra("dataforge-core")
|
||||
val spaceRepo by extra("https://maven.jetbrains.space/mipt-npm/p/df/maven")
|
||||
|
||||
allprojects {
|
||||
group = "hep.dataforge"
|
||||
version = dataforgeVersion
|
||||
|
||||
apply<org.jetbrains.dokka.gradle.DokkaPlugin>()
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "scientifik.publish")
|
||||
apply(plugin = "org.jetbrains.dokka")
|
||||
apply(plugin = "ru.mipt.npm.publish")
|
||||
}
|
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 {
|
||||
id("scientifik.mpp")
|
||||
id("ru.mipt.npm.mpp")
|
||||
id("ru.mipt.npm.native")
|
||||
}
|
||||
|
||||
description = "Context and provider definitions"
|
||||
|
||||
|
||||
useCoroutines()
|
||||
kscience {
|
||||
useCoroutines()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
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 {
|
||||
dependencies {
|
||||
api(kotlin("reflect"))
|
||||
api("io.github.microutils:kotlin-logging:1.7.9")
|
||||
api("ch.qos.logback:logback-classic:1.2.3")
|
||||
}
|
||||
}
|
||||
val jsMain by getting {
|
||||
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.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 val dependencies = ArrayList<PluginFactory<*>>()
|
||||
|
||||
@ -30,11 +30,9 @@ abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plugin {
|
||||
dependencies.add(factory)
|
||||
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> {
|
||||
override fun getValue(thisRef: AbstractPlugin, property: KProperty<*>): P {
|
||||
|
@ -1,19 +1,18 @@
|
||||
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.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.provider.Provider
|
||||
import hep.dataforge.provider.top
|
||||
import hep.dataforge.values.Value
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import mu.KLogger
|
||||
import mu.KotlinLogging
|
||||
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.
|
||||
@ -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
|
||||
* 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,
|
||||
val parent: Context? = Global
|
||||
public val parent: Context?,
|
||||
meta: Meta,
|
||||
plugins: Set<Plugin> = emptySet(),
|
||||
) : Named, MetaRepr, Provider, CoroutineScope {
|
||||
|
||||
private val config = Config()
|
||||
|
||||
/**
|
||||
* Context properties. Working as substitute for environment variables
|
||||
*/
|
||||
val properties: Meta = if (parent == null) {
|
||||
config
|
||||
private val properties: Laminate = if (parent == null) {
|
||||
Laminate(meta)
|
||||
} else {
|
||||
Laminate(config, parent.properties)
|
||||
Laminate(meta, parent.properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Context logger
|
||||
*/
|
||||
val logger: KLogger = KotlinLogging.logger(name.toString())
|
||||
public val logger: KLogger = KotlinLogging.logger(name.toString())
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Defines if context is used in any kind of active computations. Active context properties and plugins could not be changed
|
||||
*/
|
||||
val isActive: Boolean = activators.isNotEmpty()
|
||||
|
||||
override val defaultTarget: String get() = Plugin.PLUGIN_TARGET
|
||||
|
||||
override fun provideTop(target: String): Map<Name, Any> {
|
||||
return when (target) {
|
||||
Value.TYPE -> properties.sequence().toMap()
|
||||
Plugin.PLUGIN_TARGET -> plugins.sequence(true).associateBy { it.name }
|
||||
else -> emptyMap()
|
||||
public fun content(target: String, inherit: Boolean): Map<Name, Any> {
|
||||
return if (inherit) {
|
||||
when (target) {
|
||||
PROPERTY_TARGET -> properties.sequence().toMap()
|
||||
Plugin.TARGET -> plugins.list(true).associateBy { it.name }
|
||||
else -> emptyMap()
|
||||
}
|
||||
} else {
|
||||
when (target) {
|
||||
PROPERTY_TARGET -> properties.layers.firstOrNull()?.sequence()?.toMap() ?: emptyMap()
|
||||
Plugin.TARGET -> plugins.list(false).associateBy { it.name }
|
||||
else -> emptyMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 fun content(target: String): Map<Name, Any> = content(target, true)
|
||||
|
||||
override val coroutineContext: CoroutineContext by lazy {
|
||||
(parent ?: Global).coroutineContext.let { parenContext ->
|
||||
@ -101,81 +79,35 @@ open class Context(
|
||||
/**
|
||||
* Detach all plugins and terminate context
|
||||
*/
|
||||
open fun close() {
|
||||
if (isActive) error("Can't close active context")
|
||||
public open fun close() {
|
||||
//detach all plugins
|
||||
plugins.forEach { it.detach() }
|
||||
}
|
||||
|
||||
override fun toMeta(): Meta = Meta {
|
||||
"parent" to parent?.name
|
||||
"properties" put properties.seal()
|
||||
"properties" put properties.layers.firstOrNull()
|
||||
"plugins" put plugins.map { it.toMeta() }
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.content(target: String): Map<Name, Any> = content<Any>(target)
|
||||
|
||||
/**
|
||||
* 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()
|
||||
public companion object {
|
||||
public const val PROPERTY_TARGET: String = "context.property"
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
interface ContextAware {
|
||||
public interface ContextAware {
|
||||
/**
|
||||
* Get context for this object
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val context: Context
|
||||
public val context: Context
|
||||
|
||||
val logger: KLogger
|
||||
public val logger: KLogger
|
||||
get() = if (this is Named) {
|
||||
KotlinLogging.logger((context.name + this.name).toString())
|
||||
} else {
|
||||
|
@ -1,44 +1,44 @@
|
||||
package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.meta.DFBuilder
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.toName
|
||||
|
||||
/**
|
||||
* A convenience builder for context
|
||||
*/
|
||||
@DFBuilder
|
||||
class ContextBuilder(var name: String = "@anonymous", val parent: Context = Global) {
|
||||
private val plugins = ArrayList<Plugin>()
|
||||
public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") {
|
||||
private val plugins = HashSet<Plugin>()
|
||||
private var meta = MetaBuilder()
|
||||
|
||||
fun properties(action: MetaBuilder.() -> Unit) {
|
||||
public fun properties(action: MetaBuilder.() -> Unit) {
|
||||
meta.action()
|
||||
}
|
||||
|
||||
fun plugin(plugin: Plugin) {
|
||||
public fun plugin(plugin: Plugin) {
|
||||
plugins.add(plugin)
|
||||
}
|
||||
|
||||
fun plugin(tag: PluginTag, action: MetaBuilder.() -> Unit = {}) {
|
||||
plugins.add(PluginRepository.fetch(tag, Meta(action)))
|
||||
@OptIn(DFExperimental::class)
|
||||
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)))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun build(): Context {
|
||||
return Context(name.toName(), parent).apply {
|
||||
this@ContextBuilder.plugins.forEach {
|
||||
plugins.load(it)
|
||||
}
|
||||
}
|
||||
public fun build(): Context {
|
||||
return Context(name.toName(), parent, meta.seal(), plugins)
|
||||
}
|
||||
}
|
@ -2,6 +2,6 @@ package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
|
||||
interface Factory<out T : Any> {
|
||||
operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T
|
||||
public interface Factory<out T : Any> {
|
||||
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
|
||||
*/
|
||||
interface Named {
|
||||
public interface Named {
|
||||
|
||||
/**
|
||||
* 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,
|
||||
@ -42,7 +40,7 @@ interface Named {
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
fun nameOf(obj: Any): Name {
|
||||
public fun nameOf(obj: Any): Name {
|
||||
return if (obj is Named) {
|
||||
obj.name
|
||||
} else {
|
||||
@ -56,5 +54,4 @@ interface Named {
|
||||
* Check if this object has an empty name and therefore is anonymous.
|
||||
* @return
|
||||
*/
|
||||
val Named.isAnonymous: Boolean
|
||||
get() = this.name.isEmpty()
|
||||
public val Named.isAnonymous: Boolean get() = this.name.isEmpty()
|
||||
|
@ -1,43 +1,34 @@
|
||||
package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.context.Plugin.Companion.TARGET
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
import hep.dataforge.provider.Type
|
||||
|
||||
/**
|
||||
* The interface to define a Context plugin. A plugin stores all runtime features of a context.
|
||||
* 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 lifecycle is the following:
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val tag: PluginTag
|
||||
public val tag: PluginTag
|
||||
|
||||
val meta: Meta
|
||||
public val meta: Meta
|
||||
|
||||
/**
|
||||
* The name of this plugin ignoring version and group
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
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
|
||||
* dependencies must be initialized and enabled in the Context before this
|
||||
* 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
|
||||
* 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
|
||||
* plugins. This method should be called only via PluginManager to avoid
|
||||
* dependency issues.
|
||||
*/
|
||||
fun detach()
|
||||
public fun detach()
|
||||
|
||||
override fun toMeta(): Meta = Meta {
|
||||
"context" put context.name.toString()
|
||||
@ -72,9 +59,8 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
|
||||
"meta" put meta
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val PLUGIN_TARGET = "plugin"
|
||||
public companion object {
|
||||
public const val TARGET: String = "plugin"
|
||||
}
|
||||
|
||||
}
|
@ -2,42 +2,62 @@ package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.provider.Type
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@Type(PluginFactory.TYPE)
|
||||
public interface PluginFactory<T : Plugin> : Factory<T> {
|
||||
public val tag: PluginTag
|
||||
public val type: KClass<out T>
|
||||
|
||||
public companion object {
|
||||
public const val TYPE: String = "pluginFactory"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The manager for plugin system. Should monitor plugin dependencies and locks.
|
||||
*
|
||||
* @property context A context for this plugin manager
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
private val parent: PluginManager? = context.parent?.plugins
|
||||
|
||||
|
||||
fun sequence(recursive: Boolean): Sequence<Plugin> {
|
||||
return if (recursive && parent != null) {
|
||||
plugins.asSequence() + parent.sequence(true)
|
||||
/**
|
||||
* List plugins stored in this [PluginManager]. If [inherit] is true, include parent plugins as well
|
||||
*/
|
||||
public fun list(inherit: Boolean): Collection<Plugin> {
|
||||
return if (inherit && parent != null) {
|
||||
plugins + parent.list(true)
|
||||
} else {
|
||||
plugins.asSequence()
|
||||
plugins
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
@ -45,8 +65,8 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
||||
* @param tag
|
||||
* @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
|
||||
@ -60,13 +80,13 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
||||
* @return
|
||||
*/
|
||||
@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?
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
@ -76,11 +96,9 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
||||
* @param plugin
|
||||
* @return
|
||||
*/
|
||||
fun <T : Plugin> load(plugin: T): T {
|
||||
if (context.isActive) error("Can't load plugin into active context")
|
||||
|
||||
public fun <T : Plugin> load(plugin: T): T {
|
||||
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 {
|
||||
for (tag in plugin.dependsOn()) {
|
||||
fetch(tag, true)
|
||||
@ -96,18 +114,16 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
|
||||
/**
|
||||
* 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))
|
||||
|
||||
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))
|
||||
|
||||
/**
|
||||
* Remove a plugin from [PluginManager]
|
||||
*/
|
||||
fun remove(plugin: Plugin) {
|
||||
if (context.isActive) error("Can't remove plugin from active context")
|
||||
|
||||
public fun remove(plugin: Plugin) {
|
||||
if (plugins.contains(plugin)) {
|
||||
logger.info { "Removing plugin ${plugin.name} from ${context.name}" }
|
||||
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
|
||||
*
|
||||
*/
|
||||
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)
|
||||
return when {
|
||||
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>,
|
||||
recursive: Boolean = true,
|
||||
metaBuilder: MetaBuilder.() -> Unit
|
||||
metaBuilder: MetaBuilder.() -> Unit,
|
||||
): T = fetch(factory, recursive, Meta(metaBuilder))
|
||||
|
||||
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.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
|
||||
/**
|
||||
* The tag which contains information about name, group and version of some
|
||||
@ -10,7 +9,7 @@ import hep.dataforge.meta.buildMeta
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
data class PluginTag(
|
||||
public data class PluginTag(
|
||||
val name: String,
|
||||
val group: String = "",
|
||||
val version: String = ""
|
||||
@ -22,7 +21,7 @@ data class PluginTag(
|
||||
* @param otherTag
|
||||
* @return
|
||||
*/
|
||||
fun matches(otherTag: PluginTag): Boolean {
|
||||
public fun matches(otherTag: PluginTag): Boolean {
|
||||
return matchesName(otherTag) && matchesGroup(otherTag)
|
||||
}
|
||||
|
||||
@ -42,9 +41,9 @@ data class PluginTag(
|
||||
"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
|
||||
@ -52,7 +51,7 @@ data class PluginTag(
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
fun fromString(tag: String): PluginTag {
|
||||
public fun fromString(tag: String): PluginTag {
|
||||
val sepIndex = tag.indexOf(":")
|
||||
return if (sepIndex >= 0) {
|
||||
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
|
||||
* @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.
|
||||
*
|
||||
* @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()
|
||||
|
||||
companion object {
|
||||
const val PATH_SEGMENT_SEPARATOR = "/"
|
||||
public companion object {
|
||||
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 tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
|
||||
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) {
|
||||
name.toString()
|
||||
} else {
|
||||
"$target$TARGET_SEPARATOR$name"
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TARGET_SEPARATOR = "::"
|
||||
fun parse(token: String): PathToken {
|
||||
public companion object {
|
||||
public const val TARGET_SEPARATOR: String = "::"
|
||||
public fun parse(token: String): PathToken {
|
||||
val target = token.substringBefore(TARGET_SEPARATOR, "")
|
||||
val name = token.substringAfter(TARGET_SEPARATOR).toName()
|
||||
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
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.safeCast
|
||||
|
||||
/**
|
||||
* A marker utility interface for providers.
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
interface Provider {
|
||||
public interface Provider {
|
||||
|
||||
/**
|
||||
* Default target for this provider
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val defaultTarget: String get() = ""
|
||||
public val defaultTarget: String get() = ""
|
||||
|
||||
/**
|
||||
* Default target for next chain segment
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val defaultChainTarget: String get() = ""
|
||||
|
||||
public val defaultChainTarget: String get() = ""
|
||||
|
||||
/**
|
||||
* 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")
|
||||
val first = path.first()
|
||||
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) {
|
||||
1 -> res
|
||||
else -> {
|
||||
@ -65,24 +61,29 @@ fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
|
||||
/**
|
||||
* Type checked provide
|
||||
*/
|
||||
inline fun <reified T : Any> Provider.provide(path: String): T? {
|
||||
return provide(Path.parse(path)) as? T
|
||||
public inline fun <reified T : Any> Provider.provide(path: String, targetOverride: String? = null): 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? {
|
||||
return provide(PathToken(name, target).toPath()) as? T
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Provider.provide(target: String, name: String): 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
|
||||
*/
|
||||
inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> {
|
||||
return provideTop(target).mapValues {
|
||||
it.value as? T ?: error("The type of element $it is ${it::class} but ${T::class} is expected")
|
||||
public fun <T : Any> Provider.top(target: String, type: KClass<out T>): Map<Name, T> {
|
||||
return content(target).mapValues {
|
||||
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
|
||||
@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() {
|
||||
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){
|
||||
"test" -> listOf("a", "b", "c.d").associate { it.toName() to it.toName() }
|
||||
else -> emptyMap()
|
||||
@ -21,8 +21,11 @@ class ContextTest {
|
||||
|
||||
@Test
|
||||
fun testPluginManager() {
|
||||
Global.plugins.load(DummyPlugin())
|
||||
val members = Global.content<Name>("test")
|
||||
val context = Global.context("test"){
|
||||
plugin(DummyPlugin())
|
||||
}
|
||||
//Global.plugins.load(DummyPlugin())
|
||||
val members = context.gather<Name>("test")
|
||||
assertEquals(3, members.count())
|
||||
members.forEach {
|
||||
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.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)
|
||||
|
||||
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()
|
||||
.map { type.cast(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT = ClassLoaderPlugin(Global::class.java.classLoader)
|
||||
public companion object {
|
||||
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(
|
||||
|
@ -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 {
|
||||
id("scientifik.mpp")
|
||||
id("ru.mipt.npm.mpp")
|
||||
id("ru.mipt.npm.native")
|
||||
}
|
||||
|
||||
val coroutinesVersion: String = Scientifik.coroutinesVersion
|
||||
kscience{
|
||||
useCoroutines()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
val commonMain by getting{
|
||||
commonMain{
|
||||
dependencies {
|
||||
api(project(":dataforge-meta"))
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion")
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by getting{
|
||||
dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||
jvmMain{
|
||||
dependencies{
|
||||
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
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
val isTerminal: Boolean get() = false
|
||||
public val isTerminal: Boolean get() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
return object : Action<T, R> {
|
||||
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
||||
|
@ -1,48 +1,58 @@
|
||||
package hep.dataforge.data
|
||||
|
||||
import hep.dataforge.meta.DFExperimental
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
var totalWork: Double = 1.0
|
||||
var workDone: Double = 0.0
|
||||
var status: String = ""
|
||||
public var totalWork: Double = 1.0
|
||||
public var workDone: Double = 0.0
|
||||
public var status: String = ""
|
||||
|
||||
/**
|
||||
* Mark the goal as started
|
||||
*/
|
||||
fun start() {
|
||||
public fun start() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the goal as completed
|
||||
*/
|
||||
fun finish() {
|
||||
public fun finish() {
|
||||
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
|
||||
|
||||
companion object : CoroutineContext.Key<Dependencies>
|
||||
public companion object : CoroutineContext.Key<Dependencies>
|
||||
}
|
||||
|
||||
val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor]
|
||||
val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor
|
||||
@DFExperimental
|
||||
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)
|
||||
val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0)
|
||||
val Job.status: String get() = monitor?.status ?: ""
|
||||
val Job.progress: Double get() = workDone / totalWork
|
||||
@DFExperimental
|
||||
public val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0)
|
||||
@DFExperimental
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
val type: KClass<out T>
|
||||
public val type: KClass<out T>
|
||||
|
||||
/**
|
||||
* Meta for the data
|
||||
*/
|
||||
val meta: Meta
|
||||
public val meta: Meta
|
||||
|
||||
override fun toMeta(): Meta = Meta {
|
||||
"type" put (type.simpleName?:"undefined")
|
||||
@ -28,10 +29,10 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "data"
|
||||
public companion object {
|
||||
public const val TYPE: String = "data"
|
||||
|
||||
operator fun <T : Any> invoke(
|
||||
public operator fun <T : Any> invoke(
|
||||
type: KClass<out T>,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
@ -39,14 +40,14 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): 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,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
dependencies: Collection<Data<*>> = emptyList(),
|
||||
noinline block: suspend CoroutineScope.() -> T
|
||||
): Data<T> = invoke(T::class, meta, context, dependencies, block)
|
||||
|
||||
operator fun <T : Any> invoke(
|
||||
public operator fun <T : Any> invoke(
|
||||
name: String,
|
||||
type: KClass<out T>,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
@ -55,7 +56,7 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): 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,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
@ -64,13 +65,13 @@ interface Data<out T : Any> : Goal<T>, MetaRepr{
|
||||
): Data<T> =
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DynamicData<T : Any>(
|
||||
public class DynamicData<T : Any>(
|
||||
override val type: KClass<out T>,
|
||||
override val meta: Meta = Meta.EMPTY,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
@ -78,16 +79,16 @@ class DynamicData<T : Any>(
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) : Data<T>, DynamicGoal<T>(context, dependencies, block)
|
||||
|
||||
class StaticData<T : Any>(
|
||||
public class StaticData<T : Any>(
|
||||
value: T,
|
||||
override val meta: Meta = Meta.EMPTY
|
||||
) : Data<T>, StaticGoal<T>(value) {
|
||||
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>,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = this.meta,
|
||||
@ -100,7 +101,7 @@ fun <T : Any, R : Any> Data<T>.map(
|
||||
/**
|
||||
* 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,
|
||||
meta: Meta = this.meta,
|
||||
noinline block: suspend CoroutineScope.(T) -> R
|
||||
@ -111,7 +112,7 @@ inline fun <T : Any, reified R : Any> Data<T>.map(
|
||||
/**
|
||||
* 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,
|
||||
meta: Meta,
|
||||
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() } })
|
||||
}
|
||||
|
||||
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>,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
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 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,
|
||||
meta: Meta,
|
||||
noinline block: suspend CoroutineScope.(Map<K, T>) -> R
|
||||
|
@ -4,31 +4,29 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.toName
|
||||
|
||||
|
||||
class DataFilter : Scheme() {
|
||||
public class DataFilter : Scheme() {
|
||||
/**
|
||||
* A source node for the filter
|
||||
*/
|
||||
var from by string()
|
||||
public var from: String? by string()
|
||||
/**
|
||||
* A target placement for the filtered node
|
||||
*/
|
||||
var to by string()
|
||||
public var to: String? by string()
|
||||
/**
|
||||
* A regular expression pattern for the filter
|
||||
*/
|
||||
var pattern by string(".*")
|
||||
public var pattern: String by string(".*")
|
||||
// val prefix by string()
|
||||
// val suffix by string()
|
||||
|
||||
fun isEmpty(): Boolean = config.isEmpty()
|
||||
|
||||
companion object : SchemeSpec<DataFilter>(::DataFilter)
|
||||
public companion object : SchemeSpec<DataFilter>(::DataFilter)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 regex = filter.pattern.toRegex()
|
||||
val targetNode = DataTreeBuilder(type).apply {
|
||||
@ -46,10 +44,10 @@ fun <T : Any> DataNode<T>.filter(filter: DataFilter): DataNode<T> {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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))
|
@ -11,12 +11,12 @@ import kotlin.collections.component2
|
||||
import kotlin.collections.set
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
sealed class DataItem<out T : Any> : MetaRepr {
|
||||
abstract val type: KClass<out T>
|
||||
public sealed class DataItem<out T : Any> : MetaRepr {
|
||||
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 fun toMeta(): Meta = node.toMeta()
|
||||
@ -24,7 +24,7 @@ sealed class DataItem<out T : Any> : MetaRepr {
|
||||
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 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
|
||||
*/
|
||||
interface DataNode<out T : Any> : MetaRepr {
|
||||
public interface DataNode<out T : Any> : MetaRepr {
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
"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
|
||||
*/
|
||||
@Suppress("DeferredResultUnused")
|
||||
fun CoroutineScope.startAll(): Job = launch {
|
||||
public fun CoroutineScope.startAll(): Job = launch {
|
||||
items.values.forEach {
|
||||
when (it) {
|
||||
is DataItem.Node<*> -> it.node.run { startAll() }
|
||||
@ -69,36 +69,36 @@ interface DataNode<out T : Any> : MetaRepr {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "dataNode"
|
||||
public companion object {
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
val <T : Any> DataItem<T>?.data: Data<T>? get() = (this as? DataItem.Leaf<T>)?.data
|
||||
public val <T : Any> DataItem<T>?.node: DataNode<T>? get() = (this as? DataItem.Node<T>)?.node
|
||||
public val <T : Any> DataItem<T>?.data: Data<T>? get() = (this as? DataItem.Leaf<T>)?.data
|
||||
|
||||
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")
|
||||
1 -> items[name.first()]
|
||||
else -> get(name.first()!!.asName()).node?.get(name.cutFirst())
|
||||
1 -> items[name.firstOrNull()]
|
||||
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
|
||||
*/
|
||||
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) ->
|
||||
yield(head.asName() to item)
|
||||
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
|
||||
*/
|
||||
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) ->
|
||||
when (item) {
|
||||
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 items: Map<NameToken, DataItem<T>>,
|
||||
override val meta: Meta
|
||||
@ -142,17 +142,17 @@ private sealed class DataTreeBuilderItem<out T : Any> {
|
||||
* A builder for a DataTree.
|
||||
*/
|
||||
@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 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")
|
||||
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")
|
||||
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> {
|
||||
return when (name.length) {
|
||||
0 -> this
|
||||
1 -> buildNode(name.first()!!)
|
||||
else -> buildNode(name.first()!!).buildNode(name.cutFirst())
|
||||
1 -> buildNode(name.firstOrNull()!!)
|
||||
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) {
|
||||
0 -> error("Can't add data with empty name")
|
||||
1 -> set(name.first()!!, data)
|
||||
2 -> buildNode(name.cutLast())[name.last()!!] = data
|
||||
1 -> set(name.firstOrNull()!!, 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) {
|
||||
0 -> error("Can't add data with empty name")
|
||||
1 -> set(name.first()!!, node)
|
||||
2 -> buildNode(name.cutLast())[name.last()!!] = node
|
||||
1 -> set(name.firstOrNull()!!, 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.Leaf<T> -> set(name, item.data)
|
||||
}
|
||||
@ -199,25 +199,25 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
fun update(node: DataNode<T>) {
|
||||
public fun update(node: DataNode<T>) {
|
||||
node.dataSequence().forEach {
|
||||
//TODO check if the place is occupied
|
||||
this[it.first] = it.second
|
||||
@ -225,13 +225,13 @@ class DataTreeBuilder<T : Any>(val type: KClass<out T>) {
|
||||
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()
|
||||
}
|
||||
|
||||
fun build(): DataTree<T> {
|
||||
public fun build(): DataTree<T> {
|
||||
val resMap = map.mapValues { (_, value) ->
|
||||
when (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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 }
|
||||
}
|
||||
|
||||
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) ->
|
||||
if (predicate(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
|
||||
|
||||
import hep.dataforge.meta.DFExperimental
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
interface Goal<out T> {
|
||||
val dependencies: Collection<Goal<*>>
|
||||
public interface Goal<out T> {
|
||||
public val dependencies: Collection<Goal<*>>
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
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 result: Deferred<T> = CompletableDeferred(value)
|
||||
|
||||
@ -42,10 +41,10 @@ open class StaticGoal<T>(val value: T) : Goal<T> {
|
||||
}
|
||||
}
|
||||
|
||||
open class DynamicGoal<T>(
|
||||
val coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
public open class DynamicGoal<T>(
|
||||
private val coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
override val dependencies: Collection<Goal<*>> = emptyList(),
|
||||
val block: suspend CoroutineScope.() -> T
|
||||
public val block: suspend CoroutineScope.() -> T
|
||||
) : Goal<T> {
|
||||
|
||||
final override var result: Deferred<T>? = null
|
||||
@ -55,6 +54,7 @@ open class DynamicGoal<T>(
|
||||
* Get ongoing computation or start a new one.
|
||||
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
|
||||
*/
|
||||
@DFExperimental
|
||||
override fun CoroutineScope.startAsync(): Deferred<T> {
|
||||
val startedDependencies = this@DynamicGoal.dependencies.map { goal ->
|
||||
goal.run { startAsync() }
|
||||
@ -82,7 +82,7 @@ open class DynamicGoal<T>(
|
||||
/**
|
||||
* 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,
|
||||
block: suspend CoroutineScope.(T) -> R
|
||||
): Goal<R> = DynamicGoal(coroutineContext, listOf(this)) {
|
||||
@ -92,7 +92,7 @@ fun <T, R> Goal<T>.map(
|
||||
/**
|
||||
* Create a joining goal.
|
||||
*/
|
||||
fun <T, R> Collection<Goal<T>>.reduce(
|
||||
public fun <T, R> Collection<Goal<T>>.reduce(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
block: suspend CoroutineScope.(Collection<T>) -> R
|
||||
): Goal<R> = DynamicGoal(coroutineContext, this) {
|
||||
@ -105,7 +105,7 @@ fun <T, R> Collection<Goal<T>>.reduce(
|
||||
* @param T type of the input 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,
|
||||
block: suspend CoroutineScope.(Map<K, T>) -> R
|
||||
): Goal<R> = DynamicGoal(coroutineContext, this.values) {
|
||||
|
@ -19,10 +19,10 @@ import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.string
|
||||
|
||||
interface GroupRule {
|
||||
operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
|
||||
public interface GroupRule {
|
||||
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
|
||||
* field with name [key]
|
||||
@ -31,7 +31,7 @@ interface GroupRule {
|
||||
* @param defaultTagValue
|
||||
* @return
|
||||
*/
|
||||
fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
||||
public fun byValue(key: String, defaultTagValue: String): GroupRule = object :
|
||||
GroupRule {
|
||||
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
|
||||
val map = HashMap<String, DataTreeBuilder<T>>()
|
||||
@ -52,7 +52,7 @@ interface GroupRule {
|
||||
// def = "default",
|
||||
// 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
|
||||
return config["byValue"]?.string?.let {
|
||||
byValue(
|
||||
|
@ -7,32 +7,31 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* Action environment includes data name, data meta and action configuration meta
|
||||
*/
|
||||
data class ActionEnv(
|
||||
public data class ActionEnv(
|
||||
val name: Name,
|
||||
val meta: Meta,
|
||||
val actionMeta: Meta
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Action environment
|
||||
*/
|
||||
@DFBuilder
|
||||
class MapActionBuilder<T, R>(var name: Name, var meta: MetaBuilder, val actionMeta: Meta) {
|
||||
lateinit var result: suspend ActionEnv.(T) -> R
|
||||
public class MapActionBuilder<T, R>(public var name: Name, public var meta: MetaBuilder, public val actionMeta: Meta) {
|
||||
public lateinit var result: suspend ActionEnv.(T) -> R
|
||||
|
||||
/**
|
||||
* Calculate the result of goal
|
||||
*/
|
||||
fun result(f: suspend ActionEnv.(T) -> R) {
|
||||
public fun result(f: suspend ActionEnv.(T) -> R) {
|
||||
result = f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MapAction<T : Any, out R : Any>(
|
||||
val inputType: KClass<T>,
|
||||
val outputType: KClass<out R>,
|
||||
public class MapAction<T : Any, out R : Any>(
|
||||
public val inputType: KClass<T>,
|
||||
public val outputType: KClass<out R>,
|
||||
private val block: MapActionBuilder<T, R>.() -> Unit
|
||||
) : Action<T, R> {
|
||||
|
||||
@ -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,
|
||||
noinline action: MapActionBuilder<in T, out R>.() -> Unit
|
||||
): DataNode<R> = MapAction(T::class, R::class, action).invoke(this, meta)
|
||||
|
@ -7,25 +7,25 @@ import hep.dataforge.names.toName
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/**
|
||||
* 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 ->
|
||||
GroupRule.byValue(tag, defaultTag).invoke(node).map {
|
||||
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
|
||||
*/
|
||||
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 ->
|
||||
listOf(
|
||||
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 ->
|
||||
listOf(
|
||||
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
|
||||
*/
|
||||
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 ->
|
||||
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
|
||||
*/
|
||||
class ReduceAction<T : Any, R : Any>(
|
||||
val inputType: KClass<T>,
|
||||
val outputType: KClass<out R>,
|
||||
public class ReduceAction<T : Any, R : Any>(
|
||||
public val inputType: KClass<T>,
|
||||
public val outputType: KClass<out R>,
|
||||
private val action: ReduceGroupBuilder<T, R>.() -> Unit
|
||||
) : Action<T, R> {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
class FragmentRule<T : Any, R : Any>(val name: Name, var meta: MetaBuilder) {
|
||||
lateinit var result: suspend (T) -> R
|
||||
public class FragmentRule<T : Any, R : Any>(public val name: Name, public var meta: MetaBuilder) {
|
||||
public lateinit var result: suspend (T) -> R
|
||||
|
||||
fun result(f: suspend (T) -> R) {
|
||||
public fun result(f: suspend (T) -> R) {
|
||||
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()
|
||||
|
||||
/**
|
||||
@ -27,14 +27,14 @@ class SplitBuilder<T : Any, R : Any>(val name: Name, val meta: Meta) {
|
||||
* @param name the name of a fragment
|
||||
* @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
|
||||
}
|
||||
}
|
||||
|
||||
class SplitAction<T : Any, R : Any>(
|
||||
val inputType: KClass<T>,
|
||||
val outputType: KClass<out R>,
|
||||
public class SplitAction<T : Any, R : Any>(
|
||||
public val inputType: KClass<T>,
|
||||
public val outputType: KClass<out R>,
|
||||
private val action: SplitBuilder<T, R>.() -> Unit
|
||||
) : Action<T, R> {
|
||||
|
||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
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 {
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.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
|
||||
*/
|
||||
@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> {
|
||||
override val meta: Meta get() = this@cast.meta
|
||||
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")
|
||||
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> {
|
||||
override val meta: Meta get() = this@cast.meta
|
||||
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
|
||||
*/
|
||||
fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
|
||||
public fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
|
||||
if (!canCast(type)) {
|
||||
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
|
||||
*/
|
||||
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
|
||||
//Not supported in js yet
|
||||
return true
|
||||
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
|
||||
return this.type == type
|
||||
}
|
||||
|
||||
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
|
||||
//Not supported in js yet
|
||||
return true
|
||||
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
|
||||
return this.type == type
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* 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 items: Map<NameToken, DataItem<T>> by lazy {
|
||||
origin.items.mapNotNull { (key, item) ->
|
||||
|
@ -3,33 +3,32 @@ package hep.dataforge.data
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.isSuperclassOf
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
|
||||
type.isSuperclassOf(type)
|
||||
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
|
||||
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)
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 {
|
||||
canCast(type) -> cast(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.
|
||||
*/
|
||||
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
|
||||
is DataItem.Node -> DataItem.Node(this.node.filterIsInstance(type))
|
||||
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 {
|
||||
id("scientifik.mpp")
|
||||
id("ru.mipt.npm.mpp")
|
||||
id("ru.mipt.npm.native")
|
||||
}
|
||||
|
||||
description = "IO module"
|
||||
|
||||
useSerialization(sourceSet = TEST){
|
||||
cbor()
|
||||
kscience {
|
||||
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 {
|
||||
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 {
|
||||
id("scientifik.jvm")
|
||||
id("ru.mipt.npm.jvm")
|
||||
}
|
||||
|
||||
description = "YAML meta IO"
|
||||
|
||||
useSerialization{
|
||||
yaml()
|
||||
kscience {
|
||||
useSerialization {
|
||||
yaml()
|
||||
}
|
||||
}
|
||||
|
||||
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.text.readUtf8Line
|
||||
import kotlinx.io.text.writeUtf8String
|
||||
import kotlinx.serialization.toUtf8Bytes
|
||||
|
||||
@DFExperimental
|
||||
class FrontMatterEnvelopeFormat(
|
||||
val io: IOPlugin,
|
||||
val meta: Meta = Meta.EMPTY
|
||||
public class FrontMatterEnvelopeFormat(
|
||||
private val io: IOPlugin,
|
||||
private val meta: Meta = Meta.EMPTY,
|
||||
) : EnvelopeFormat {
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope {
|
||||
var line: String = ""
|
||||
override fun readPartial(input: Input): PartialEnvelope {
|
||||
var line = ""
|
||||
var offset = 0u
|
||||
do {
|
||||
line = readUtf8Line() //?: error("Input does not contain front matter separator")
|
||||
offset += line.toUtf8Bytes().size.toUInt()
|
||||
line = input.readUtf8Line() //?: error("Input does not contain front matter separator")
|
||||
offset += line.toByteArray().size.toUInt()
|
||||
} while (!line.startsWith(SEPARATOR))
|
||||
|
||||
val readMetaFormat =
|
||||
@ -32,22 +31,21 @@ class FrontMatterEnvelopeFormat(
|
||||
//TODO replace by preview
|
||||
val meta = Binary {
|
||||
do {
|
||||
line = readUtf8Line()
|
||||
line = input.readUtf8Line()
|
||||
writeUtf8String(line + "\r\n")
|
||||
offset += line.toUtf8Bytes().size.toUInt()
|
||||
offset += line.toByteArray().size.toUInt()
|
||||
} while (!line.startsWith(SEPARATOR))
|
||||
}.read {
|
||||
readMetaFormat.run {
|
||||
readMeta()
|
||||
}
|
||||
readMetaFormat.readMeta(input)
|
||||
|
||||
}
|
||||
return PartialEnvelope(meta, offset, null)
|
||||
}
|
||||
|
||||
override fun Input.readObject(): Envelope {
|
||||
var line: String = ""
|
||||
override fun readObject(input: Input): Envelope {
|
||||
var line = ""
|
||||
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))
|
||||
|
||||
val readMetaFormat =
|
||||
@ -56,26 +54,29 @@ class FrontMatterEnvelopeFormat(
|
||||
|
||||
val meta = Binary {
|
||||
do {
|
||||
writeUtf8String(readUtf8Line() + "\r\n")
|
||||
writeUtf8String(input.readUtf8Line() + "\r\n")
|
||||
} while (!line.startsWith(SEPARATOR))
|
||||
}.read {
|
||||
readMetaFormat.run {
|
||||
readMeta()
|
||||
}
|
||||
readMetaFormat.readMeta(input)
|
||||
}
|
||||
val bytes = readByteArray()
|
||||
val bytes = input.readByteArray()
|
||||
val data = bytes.asBinary()
|
||||
return SimpleEnvelope(meta, data)
|
||||
}
|
||||
|
||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
||||
val metaFormat = metaFormatFactory(formatMeta, io.context)
|
||||
writeRawString("$SEPARATOR\r\n")
|
||||
metaFormat.run { writeObject(envelope.meta) }
|
||||
writeRawString("$SEPARATOR\r\n")
|
||||
override fun writeEnvelope(
|
||||
output: Output,
|
||||
envelope: Envelope,
|
||||
metaFormatFactory: MetaFormatFactory,
|
||||
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
|
||||
envelope.data?.let { data ->
|
||||
writeBinary(data)
|
||||
output.writeBinary(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,8 +85,8 @@ class FrontMatterEnvelopeFormat(
|
||||
META_KEY put meta
|
||||
}
|
||||
|
||||
companion object : EnvelopeFormatFactory {
|
||||
const val SEPARATOR = "---"
|
||||
public companion object : EnvelopeFormatFactory {
|
||||
public const val SEPARATOR = "---"
|
||||
|
||||
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
|
||||
|
||||
@ -106,14 +107,18 @@ class FrontMatterEnvelopeFormat(
|
||||
|
||||
private val default by lazy { invoke() }
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope =
|
||||
default.run { readPartial() }
|
||||
override fun readPartial(input: Input): PartialEnvelope =
|
||||
default.readPartial(input)
|
||||
|
||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) =
|
||||
default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) }
|
||||
override fun writeEnvelope(
|
||||
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 org.yaml.snakeyaml.Yaml
|
||||
|
||||
/**
|
||||
* Represent meta as Yaml
|
||||
*/
|
||||
@DFExperimental
|
||||
class YamlMetaFormat(val meta: Meta) : MetaFormat {
|
||||
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
|
||||
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))
|
||||
writeUtf8String(string)
|
||||
output.writeUtf8String(string)
|
||||
}
|
||||
|
||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
||||
val map: Map<String, Any?> = yaml.load(asInputStream())
|
||||
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||
val map: Map<String, Any?> = yaml.load(input.asInputStream())
|
||||
return map.toMeta(descriptor)
|
||||
}
|
||||
|
||||
@ -35,19 +38,19 @@ class YamlMetaFormat(val meta: Meta) : MetaFormat {
|
||||
META_KEY put meta
|
||||
}
|
||||
|
||||
companion object : MetaFormatFactory {
|
||||
public companion object : MetaFormatFactory {
|
||||
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
|
||||
|
||||
private val default = YamlMetaFormat()
|
||||
|
||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) =
|
||||
default.run { writeMeta(meta, descriptor) }
|
||||
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
||||
default.writeMeta(output, meta, descriptor)
|
||||
|
||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta =
|
||||
default.run { readMeta(descriptor) }
|
||||
override fun readMeta(input: kotlinx.io.Input, descriptor: NodeDescriptor?): Meta =
|
||||
default.readMeta(input, descriptor)
|
||||
}
|
||||
}
|
@ -11,14 +11,18 @@ import kotlinx.io.*
|
||||
import kotlinx.io.text.readUtf8String
|
||||
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 key: Short = 0x4249//BI
|
||||
|
||||
override fun invoke(meta: Meta, context: Context): MetaFormat = this
|
||||
|
||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
||||
return (readMetaItem() as MetaItem.NodeItem).node
|
||||
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||
return (input.readMetaItem() as MetaItem.NodeItem).node
|
||||
}
|
||||
|
||||
private fun Output.writeChar(char: Char) = writeByte(char.toByte())
|
||||
@ -28,7 +32,7 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
||||
writeUtf8String(str)
|
||||
}
|
||||
|
||||
fun Output.writeValue(value: Value) {
|
||||
public fun Output.writeValue(value: Value) {
|
||||
if (value.isList()) {
|
||||
writeChar('L')
|
||||
writeInt(value.list.size)
|
||||
@ -75,17 +79,21 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
||||
}
|
||||
}
|
||||
|
||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
|
||||
writeChar('M')
|
||||
writeInt(meta.items.size)
|
||||
override fun writeMeta(
|
||||
output: kotlinx.io.Output,
|
||||
meta: hep.dataforge.meta.Meta,
|
||||
descriptor: hep.dataforge.meta.descriptors.NodeDescriptor?
|
||||
) {
|
||||
output.writeChar('M')
|
||||
output.writeInt(meta.items.size)
|
||||
meta.items.forEach { (key, item) ->
|
||||
writeString(key.toString())
|
||||
output.writeString(key.toString())
|
||||
when (item) {
|
||||
is MetaItem.ValueItem -> {
|
||||
writeValue(item.value)
|
||||
output.writeValue(item.value)
|
||||
}
|
||||
is MetaItem.NodeItem -> {
|
||||
writeObject(item.node)
|
||||
writeObject(output, item.node)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,7 +105,7 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
||||
public fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
||||
return when (val keyChar = readByte().toChar()) {
|
||||
'S' -> MetaItem.ValueItem(StringValue(readString()))
|
||||
'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.get
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import kotlinx.io.Binary
|
||||
|
||||
interface Envelope {
|
||||
val meta: Meta
|
||||
val data: Binary?
|
||||
public interface Envelope {
|
||||
public val meta: Meta
|
||||
public val data: Binary?
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
|
||||
/**
|
||||
* meta keys
|
||||
*/
|
||||
val ENVELOPE_NODE_KEY = "@envelope".asName()
|
||||
val ENVELOPE_TYPE_KEY = ENVELOPE_NODE_KEY + "type"
|
||||
val ENVELOPE_DATA_TYPE_KEY = ENVELOPE_NODE_KEY + "dataType"
|
||||
val ENVELOPE_DATA_ID_KEY = ENVELOPE_NODE_KEY + "dataID"
|
||||
val ENVELOPE_DESCRIPTION_KEY = ENVELOPE_NODE_KEY + "description"
|
||||
val ENVELOPE_NAME_KEY = ENVELOPE_NODE_KEY + "name"
|
||||
public val ENVELOPE_NODE_KEY: Name = "@envelope".asName()
|
||||
public val ENVELOPE_TYPE_KEY: Name = ENVELOPE_NODE_KEY + "type"
|
||||
public val ENVELOPE_DATA_TYPE_KEY: Name = ENVELOPE_NODE_KEY + "dataType"
|
||||
public val ENVELOPE_DATA_ID_KEY: Name = ENVELOPE_NODE_KEY + "dataID"
|
||||
public val ENVELOPE_DESCRIPTION_KEY: Name = ENVELOPE_NODE_KEY + "description"
|
||||
public val ENVELOPE_NAME_KEY: Name = ENVELOPE_NODE_KEY + "name"
|
||||
//const val ENVELOPE_TIME_KEY = "@envelope.time"
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
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
|
||||
*
|
||||
*/
|
||||
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
|
||||
*
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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)))
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
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 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)
|
||||
*/
|
||||
fun Envelope.withMetaLayers(vararg layers: Meta): Envelope {
|
||||
public fun Envelope.withMetaLayers(vararg layers: Meta): Envelope {
|
||||
return when {
|
||||
layers.isEmpty() -> this
|
||||
this is ProxyEnvelope -> ProxyEnvelope(source, *layers, *this.meta.layers.toTypedArray())
|
||||
|
@ -3,42 +3,44 @@ package hep.dataforge.io
|
||||
import hep.dataforge.meta.*
|
||||
import kotlinx.io.*
|
||||
|
||||
class EnvelopeBuilder {
|
||||
public class EnvelopeBuilder : Envelope {
|
||||
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)
|
||||
}
|
||||
|
||||
fun meta(meta: Meta) {
|
||||
metaBuilder.update(meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* The general purpose of the envelope
|
||||
*/
|
||||
var type by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
|
||||
var dataType by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
|
||||
public var type: String? by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
|
||||
public var dataType: String? by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
|
||||
|
||||
/**
|
||||
* Data unique identifier to bypass identity checks
|
||||
*/
|
||||
var dataID by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
|
||||
var description by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
|
||||
var name by metaBuilder.string(key = Envelope.ENVELOPE_NAME_KEY)
|
||||
public var dataID: String? by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
|
||||
public var description: String? by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
|
||||
public var name: String? by metaBuilder.string(key = Envelope.ENVELOPE_NAME_KEY)
|
||||
|
||||
/**
|
||||
* Construct a data binary from given builder
|
||||
*/
|
||||
@OptIn(ExperimentalIoApi::class)
|
||||
fun data(block: Output.() -> Unit) {
|
||||
public fun data(block: Output.() -> Unit) {
|
||||
val arrayBuilder = ByteArrayOutput()
|
||||
arrayBuilder.block()
|
||||
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
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: ULong?)
|
||||
public data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: ULong?)
|
||||
|
||||
interface EnvelopeFormat : IOFormat<Envelope> {
|
||||
val defaultMetaFormat: MetaFormatFactory get() = JsonMetaFormat
|
||||
public interface EnvelopeFormat : IOFormat<Envelope> {
|
||||
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,
|
||||
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()
|
||||
|
||||
fun EnvelopeFormat.read(input: Input) = input.readObject()
|
||||
public fun EnvelopeFormat.read(input: Input): Envelope = readObject(input)
|
||||
|
||||
@Type(ENVELOPE_FORMAT_TYPE)
|
||||
interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
|
||||
public interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
|
||||
override val name: Name get() = "envelope".asName()
|
||||
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.
|
||||
* 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 {
|
||||
const val ENVELOPE_FORMAT_TYPE = "io.format.envelope"
|
||||
public companion object {
|
||||
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,
|
||||
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
||||
) {
|
||||
@ -69,7 +69,7 @@ fun EnvelopeBuilder.multipart(
|
||||
}
|
||||
}
|
||||
|
||||
fun EnvelopeBuilder.envelopes(
|
||||
public fun EnvelopeBuilder.envelopes(
|
||||
envelopes: List<Envelope>,
|
||||
format: EnvelopeFormat = TaggedEnvelopeFormat,
|
||||
separator: String = DEFAULT_MULTIPART_DATA_SEPARATOR
|
||||
@ -84,11 +84,11 @@ fun EnvelopeBuilder.envelopes(
|
||||
multipart(parts, separator)
|
||||
}
|
||||
|
||||
fun Envelope.parts(): EnvelopeParts {
|
||||
public fun Envelope.parts(): EnvelopeParts {
|
||||
if (data == null) return emptyList()
|
||||
//TODO add zip folder reader
|
||||
val parts = meta.getIndexed(PARTS_KEY).values.mapNotNull { it.node }.map {
|
||||
PartDescriptor.wrap(it)
|
||||
PartDescriptor.read(it)
|
||||
}
|
||||
return if (parts.isEmpty()) {
|
||||
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
|
||||
*/
|
||||
fun EnvelopePart.envelope(plugin: IOPlugin): Envelope {
|
||||
public fun EnvelopePart.envelope(plugin: IOPlugin): Envelope {
|
||||
val formatItem = description?.get(PART_FORMAT_KEY)
|
||||
return if (formatItem != null) {
|
||||
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
|
||||
*/
|
||||
interface IOFormat<T : Any> : MetaRepr {
|
||||
fun Output.writeObject(obj: T)
|
||||
fun Input.readObject(): T
|
||||
public interface IOFormat<T : Any> : MetaRepr {
|
||||
public fun writeObject(output: Output, obj: T)
|
||||
public fun readObject(input: Input): T
|
||||
|
||||
companion object{
|
||||
val NAME_KEY = "name".asName()
|
||||
val META_KEY = "meta".asName()
|
||||
public companion object {
|
||||
public val NAME_KEY: Name = "name".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
|
||||
*/
|
||||
fun <T : Any> Binary.readWith(format: IOFormat<T>): T = read {
|
||||
public fun <T : Any> Binary.readWith(format: IOFormat<T>): T = read {
|
||||
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>> {
|
||||
override fun Output.writeObject(obj: List<T>) {
|
||||
writeInt(obj.size)
|
||||
format.run {
|
||||
public class ListIOFormat<T : Any>(public val format: IOFormat<T>) : IOFormat<List<T>> {
|
||||
override fun writeObject(output: Output, obj: List<T>) {
|
||||
output.writeInt(obj.size)
|
||||
this.format.run {
|
||||
obj.forEach {
|
||||
writeObject(it)
|
||||
writeObject(output, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Input.readObject(): List<T> {
|
||||
val size = readInt()
|
||||
override fun readObject(input: Input): List<T> {
|
||||
val size = input.readInt()
|
||||
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()
|
||||
return try {
|
||||
buffer.apply(block)
|
||||
@ -77,50 +78,50 @@ fun ObjectPool<Buffer>.fill(block: Buffer.() -> Unit): Buffer {
|
||||
}
|
||||
|
||||
@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
|
||||
*/
|
||||
val type: KClass<out T>
|
||||
public val type: KClass<out T>
|
||||
|
||||
override fun toMeta(): Meta = Meta {
|
||||
NAME_KEY put name.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val IO_FORMAT_TYPE = "io.format"
|
||||
public companion object {
|
||||
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 val name: Name = "double".asName()
|
||||
|
||||
override val type: KClass<out Double> get() = Double::class
|
||||
|
||||
override fun Output.writeObject(obj: Double) {
|
||||
writeDouble(obj)
|
||||
override fun writeObject(output: Output, obj: kotlin.Double) {
|
||||
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 val name: Name = "value".asName()
|
||||
|
||||
override val type: KClass<out Value> get() = Value::class
|
||||
|
||||
override fun Output.writeObject(obj: Value) {
|
||||
BinaryMetaFormat.run { writeValue(obj) }
|
||||
override fun writeObject(output: Output, obj: Value) {
|
||||
BinaryMetaFormat.run { output.writeValue(obj) }
|
||||
}
|
||||
|
||||
override fun Input.readObject(): Value {
|
||||
return (BinaryMetaFormat.run { readMetaItem() } as? MetaItem.ValueItem)?.value
|
||||
override fun readObject(input: Input): Value {
|
||||
return (BinaryMetaFormat.run { input.readMetaItem() } as? MetaItem.ValueItem)?.value
|
||||
?: error("The item is not a value")
|
||||
}
|
||||
}
|
@ -11,14 +11,14 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
|
||||
val ioFormatFactories by lazy {
|
||||
context.content<IOFormatFactory<*>>(IO_FORMAT_TYPE).values
|
||||
public val ioFormatFactories: Collection<IOFormatFactory<*>> by lazy {
|
||||
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 name = key.toName()
|
||||
return ioFormatFactories.find { it.name == name }?.let {
|
||||
@ -29,40 +29,40 @@ class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
}
|
||||
|
||||
|
||||
val metaFormatFactories by lazy {
|
||||
context.content<MetaFormatFactory>(META_FORMAT_TYPE).values
|
||||
public val metaFormatFactories: Collection<MetaFormatFactory> by lazy {
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
val envelopeFormatFactories by lazy {
|
||||
context.content<EnvelopeFormatFactory>(ENVELOPE_FORMAT_TYPE).values
|
||||
public val envelopeFormatFactories: Collection<EnvelopeFormatFactory> by lazy {
|
||||
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)
|
||||
|
||||
fun resolveEnvelopeFormat(item: MetaItem<*>): EnvelopeFormat? {
|
||||
public fun resolveEnvelopeFormat(item: MetaItem<*>): EnvelopeFormat? {
|
||||
val name = item.string ?: item.node[NAME_KEY]?.string ?: error("Envelope format name not defined")
|
||||
val meta = item.node[META_KEY].node ?: Meta.EMPTY
|
||||
return resolveEnvelopeFormat(name.toName(), meta)
|
||||
}
|
||||
|
||||
override fun provideTop(target: String): Map<Name, Any> {
|
||||
override fun content(target: String): Map<Name, Any> {
|
||||
return when (target) {
|
||||
META_FORMAT_TYPE -> defaultMetaFormats.toMap()
|
||||
ENVELOPE_FORMAT_TYPE -> defaultEnvelopeFormats.toMap()
|
||||
else -> super.provideTop(target)
|
||||
else -> super.content(target)
|
||||
}
|
||||
}
|
||||
|
||||
companion object : PluginFactory<IOPlugin> {
|
||||
val defaultMetaFormats: List<MetaFormatFactory> = listOf(JsonMetaFormat, BinaryMetaFormat)
|
||||
val defaultEnvelopeFormats = listOf(TaggedEnvelopeFormat, TaglessEnvelopeFormat)
|
||||
public companion object : PluginFactory<IOPlugin> {
|
||||
public val defaultMetaFormats: List<MetaFormatFactory> = listOf(JsonMetaFormat, BinaryMetaFormat)
|
||||
public val defaultEnvelopeFormats: List<EnvelopeFormatFactory> = listOf(TaggedEnvelopeFormat, TaglessEnvelopeFormat)
|
||||
|
||||
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 kotlinx.io.Input
|
||||
import kotlinx.io.Output
|
||||
import kotlinx.io.readByteArray
|
||||
import kotlinx.io.text.readUtf8String
|
||||
import kotlinx.io.text.writeUtf8String
|
||||
import kotlinx.serialization.UnstableDefault
|
||||
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)
|
||||
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()
|
||||
}
|
||||
|
||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
|
||||
val str = readByteArray().decodeToString()
|
||||
val jsonElement = json.parseJson(str)
|
||||
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||
val str = input.readUtf8String()//readByteArray().decodeToString()
|
||||
val jsonElement = json.parseToJsonElement(str)
|
||||
val item = jsonElement.toMetaItem(descriptor)
|
||||
return item.node ?: Meta.EMPTY
|
||||
}
|
||||
|
||||
companion object : MetaFormatFactory {
|
||||
val DEFAULT_JSON = Json { prettyPrint = true }
|
||||
public companion object : MetaFormatFactory {
|
||||
public val DEFAULT_JSON: Json = Json { prettyPrint = true }
|
||||
|
||||
override fun invoke(meta: Meta, context: Context): MetaFormat = default
|
||||
|
||||
override val shortName = "json"
|
||||
override val shortName: String = "json"
|
||||
override val key: Short = 0x4a53//"JS"
|
||||
|
||||
private val default = JsonMetaFormat()
|
||||
|
||||
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) =
|
||||
default.run { writeMeta(meta, descriptor) }
|
||||
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
||||
default.run { writeMeta(output, meta, descriptor) }
|
||||
|
||||
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta =
|
||||
default.run { readMeta(descriptor) }
|
||||
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta =
|
||||
default.run { readMeta(input, descriptor) }
|
||||
}
|
||||
}
|
||||
|
@ -17,46 +17,50 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* A format for meta serialization
|
||||
*/
|
||||
public interface MetaFormat : IOFormat<Meta> {
|
||||
|
||||
interface MetaFormat : IOFormat<Meta> {
|
||||
|
||||
override fun Output.writeObject(obj: Meta) {
|
||||
writeMeta(obj, null)
|
||||
override fun writeObject(output: Output, obj: Meta) {
|
||||
writeMeta(output, obj, null)
|
||||
}
|
||||
|
||||
override fun Input.readObject(): Meta = readMeta()
|
||||
override fun readObject(input: Input): Meta = readMeta(input)
|
||||
|
||||
fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor? = null)
|
||||
fun Input.readMeta(descriptor: NodeDescriptor? = null): Meta
|
||||
public fun writeMeta(
|
||||
output: Output,
|
||||
meta: Meta,
|
||||
descriptor: NodeDescriptor? = null,
|
||||
)
|
||||
|
||||
public fun readMeta(input: Input, descriptor: NodeDescriptor? = null): Meta
|
||||
}
|
||||
|
||||
@Type(META_FORMAT_TYPE)
|
||||
interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
|
||||
val shortName: String
|
||||
public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
|
||||
public val shortName: String
|
||||
|
||||
override val name: Name get() = "meta".asName() + shortName
|
||||
|
||||
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
|
||||
|
||||
companion object {
|
||||
const val META_FORMAT_TYPE = "io.format.meta"
|
||||
public companion object {
|
||||
public const val META_FORMAT_TYPE: String = "io.format.meta"
|
||||
}
|
||||
}
|
||||
|
||||
fun Meta.toString(format: MetaFormat): String = buildByteArray {
|
||||
format.run { writeObject(this@toString) }
|
||||
public fun Meta.toString(format: MetaFormat): String = buildByteArray {
|
||||
format.run { writeObject(this@buildByteArray, this@toString) }
|
||||
}.decodeToString()
|
||||
|
||||
fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory())
|
||||
public fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory())
|
||||
|
||||
fun MetaFormat.parse(str: String): Meta {
|
||||
return ByteArrayInput(str.encodeToByteArray()).use { it.readObject() }
|
||||
public fun MetaFormat.parse(str: String): Meta {
|
||||
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
|
||||
|
||||
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
|
||||
*/
|
||||
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 kotlinx.io.*
|
||||
|
||||
class TaggedEnvelopeFormat(
|
||||
val io: IOPlugin,
|
||||
val version: VERSION = VERSION.DF02
|
||||
/**
|
||||
* A streaming-friendly envelope format with a short binary tag.
|
||||
* TODO add description
|
||||
*/
|
||||
public class TaggedEnvelopeFormat(
|
||||
public val io: IOPlugin,
|
||||
public val version: VERSION = VERSION.DF02,
|
||||
) : EnvelopeFormat {
|
||||
|
||||
// private val metaFormat = io.metaFormat(metaFormatKey)
|
||||
@ -37,18 +41,23 @@ class TaggedEnvelopeFormat(
|
||||
writeRawString(END_SEQUENCE)
|
||||
}
|
||||
|
||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
||||
val metaFormat = metaFormatFactory.invoke(formatMeta, io.context)
|
||||
override fun writeEnvelope(
|
||||
output: Output,
|
||||
envelope: Envelope,
|
||||
metaFormatFactory: MetaFormatFactory,
|
||||
formatMeta: Meta,
|
||||
) {
|
||||
val metaFormat = metaFormatFactory.invoke(formatMeta, this@TaggedEnvelopeFormat.io.context)
|
||||
val metaBytes = metaFormat.toBinary(envelope.meta)
|
||||
val actualSize: ULong = (envelope.data?.size ?: 0).toULong()
|
||||
val tag = Tag(metaFormatFactory.key, metaBytes.size.toUInt() + 2u, actualSize)
|
||||
writeBinary(tag.toBinary())
|
||||
writeBinary(metaBytes)
|
||||
writeRawString("\r\n")
|
||||
output.writeBinary(tag.toBinary())
|
||||
output.writeBinary(metaBytes)
|
||||
output.writeRawString("\r\n")
|
||||
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 formats a collection of meta formats to resolve
|
||||
*/
|
||||
override fun Input.readObject(): Envelope {
|
||||
val tag = readTag(version)
|
||||
override fun readObject(input: Input): Envelope {
|
||||
val tag = input.readTag(this.version)
|
||||
|
||||
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
||||
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
||||
|
||||
val meta: Meta = limit(tag.metaSize.toInt()).run {
|
||||
metaFormat.run {
|
||||
readObject()
|
||||
}
|
||||
}
|
||||
val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt()))
|
||||
|
||||
val data = readBinary(tag.dataSize.toInt())
|
||||
val data = input.readBinary(tag.dataSize.toInt())
|
||||
|
||||
return SimpleEnvelope(meta, data)
|
||||
}
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope {
|
||||
val tag = readTag(version)
|
||||
override fun readPartial(input: Input): PartialEnvelope {
|
||||
val tag = input.readTag(this.version)
|
||||
|
||||
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
|
||||
?: error("Meta format with key ${tag.metaFormatKey} not found")
|
||||
|
||||
val meta: Meta = limit(tag.metaSize.toInt()).run {
|
||||
metaFormat.run {
|
||||
readObject()
|
||||
}
|
||||
}
|
||||
val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt()))
|
||||
|
||||
|
||||
return PartialEnvelope(meta, version.tagSize + tag.metaSize, tag.dataSize)
|
||||
}
|
||||
@ -92,10 +94,10 @@ class TaggedEnvelopeFormat(
|
||||
private data class Tag(
|
||||
val metaFormatKey: Short,
|
||||
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),
|
||||
DF03(24u)
|
||||
}
|
||||
@ -107,7 +109,7 @@ class TaggedEnvelopeFormat(
|
||||
}
|
||||
}
|
||||
|
||||
companion object : EnvelopeFormatFactory {
|
||||
public companion object : EnvelopeFormatFactory {
|
||||
private const val START_SEQUENCE = "#~"
|
||||
private const val END_SEQUENCE = "~#\r\n"
|
||||
|
||||
@ -158,16 +160,24 @@ class TaggedEnvelopeFormat(
|
||||
|
||||
private val default by lazy { invoke() }
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope =
|
||||
default.run { readPartial() }
|
||||
|
||||
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 readPartial(input: Input): PartialEnvelope =
|
||||
default.run { readPartial(input) }
|
||||
|
||||
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.isEmpty
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import kotlinx.io.*
|
||||
import kotlinx.io.text.readUtf8Line
|
||||
import kotlinx.io.text.writeUtf8String
|
||||
import kotlin.collections.set
|
||||
|
||||
class TaglessEnvelopeFormat(
|
||||
val io: IOPlugin,
|
||||
val meta: Meta = Meta.EMPTY
|
||||
/**
|
||||
* A text envelope format with human-readable tag.
|
||||
* TODO add description
|
||||
*/
|
||||
public class TaglessEnvelopeFormat(
|
||||
public val io: IOPlugin,
|
||||
public val meta: Meta = Meta.EMPTY,
|
||||
) : EnvelopeFormat {
|
||||
|
||||
private val metaStart = meta[META_START_PROPERTY].string ?: DEFAULT_META_START
|
||||
@ -25,39 +30,46 @@ class TaglessEnvelopeFormat(
|
||||
writeUtf8String("#? $key: $value;\r\n")
|
||||
}
|
||||
|
||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) {
|
||||
val metaFormat = metaFormatFactory(formatMeta, io.context)
|
||||
override fun writeEnvelope(
|
||||
output: Output,
|
||||
envelope: Envelope,
|
||||
metaFormatFactory: MetaFormatFactory,
|
||||
formatMeta: Meta
|
||||
) {
|
||||
val metaFormat = metaFormatFactory(formatMeta, this.io.context)
|
||||
|
||||
//printing header
|
||||
writeRawString(TAGLESS_ENVELOPE_HEADER + "\r\n")
|
||||
output.writeRawString(TAGLESS_ENVELOPE_HEADER + "\r\n")
|
||||
|
||||
//printing all properties
|
||||
writeProperty(META_TYPE_PROPERTY, metaFormatFactory.shortName)
|
||||
output.writeProperty(META_TYPE_PROPERTY,
|
||||
metaFormatFactory.shortName)
|
||||
//TODO add optional metaFormat properties
|
||||
val actualSize: Int = envelope.data?.size ?: 0
|
||||
|
||||
writeProperty(DATA_LENGTH_PROPERTY, actualSize)
|
||||
output.writeProperty(DATA_LENGTH_PROPERTY, actualSize)
|
||||
|
||||
//Printing meta
|
||||
if (!envelope.meta.isEmpty()) {
|
||||
val metaBytes = metaFormat.toBinary(envelope.meta)
|
||||
writeProperty(META_LENGTH_PROPERTY, metaBytes.size + 2)
|
||||
writeUtf8String(metaStart + "\r\n")
|
||||
writeBinary(metaBytes)
|
||||
writeRawString("\r\n")
|
||||
output.writeProperty(META_LENGTH_PROPERTY,
|
||||
metaBytes.size + 2)
|
||||
output.writeUtf8String(this.metaStart + "\r\n")
|
||||
output.writeBinary(metaBytes)
|
||||
output.writeRawString("\r\n")
|
||||
}
|
||||
|
||||
//Printing data
|
||||
envelope.data?.let { data ->
|
||||
writeUtf8String(dataStart + "\r\n")
|
||||
writeBinary(data)
|
||||
output.writeUtf8String(this.dataStart + "\r\n")
|
||||
output.writeBinary(data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun Input.readObject(): Envelope {
|
||||
override fun readObject(input: Input): Envelope {
|
||||
var line: String
|
||||
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))
|
||||
val properties = HashMap<String, String>()
|
||||
|
||||
@ -70,8 +82,8 @@ class TaglessEnvelopeFormat(
|
||||
properties[key] = value
|
||||
}
|
||||
//If can't read line, return envelope without data
|
||||
if (exhausted()) return SimpleEnvelope(Meta.EMPTY, null)
|
||||
line = readUtf8Line()
|
||||
if (input.exhausted()) return SimpleEnvelope(Meta.EMPTY, null)
|
||||
line = input.readUtf8Line()
|
||||
}
|
||||
|
||||
var meta: Meta = Meta.EMPTY
|
||||
@ -80,19 +92,15 @@ class TaglessEnvelopeFormat(
|
||||
val metaFormat = properties[META_TYPE_PROPERTY]?.let { io.resolveMetaFormat(it) } ?: JsonMetaFormat
|
||||
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
||||
meta = if (metaSize != null) {
|
||||
limit(metaSize).run {
|
||||
metaFormat.run { readObject() }
|
||||
}
|
||||
metaFormat.readObject(input.limit(metaSize))
|
||||
} else {
|
||||
metaFormat.run {
|
||||
readObject()
|
||||
}
|
||||
metaFormat.readObject(input)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
try {
|
||||
line = readUtf8Line()
|
||||
line = input.readUtf8Line()
|
||||
} catch (ex: EOFException) {
|
||||
//returning an Envelope without data if end of input is reached
|
||||
return SimpleEnvelope(meta, null)
|
||||
@ -100,24 +108,24 @@ class TaglessEnvelopeFormat(
|
||||
} while (!line.startsWith(dataStart))
|
||||
|
||||
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())
|
||||
// readByteArray(bytes)
|
||||
// bytes.asBinary()
|
||||
} else {
|
||||
Binary {
|
||||
copyTo(this)
|
||||
input.copyTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleEnvelope(meta, data)
|
||||
}
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope {
|
||||
override fun readPartial(input: Input): PartialEnvelope {
|
||||
var offset = 0u
|
||||
var line: String
|
||||
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()
|
||||
} while (!line.startsWith(TAGLESS_ENVELOPE_HEADER))
|
||||
val properties = HashMap<String, String>()
|
||||
@ -131,7 +139,7 @@ class TaglessEnvelopeFormat(
|
||||
properties[key] = value
|
||||
}
|
||||
try {
|
||||
line = readUtf8Line()
|
||||
line = input.readUtf8Line()
|
||||
offset += line.encodeToByteArray().size.toUInt()
|
||||
} catch (ex: EOFException) {
|
||||
return PartialEnvelope(Meta.EMPTY, offset.toUInt(), 0.toULong())
|
||||
@ -145,16 +153,14 @@ class TaglessEnvelopeFormat(
|
||||
val metaSize = properties[META_LENGTH_PROPERTY]?.toInt()
|
||||
meta = if (metaSize != null) {
|
||||
offset += metaSize.toUInt()
|
||||
limit(metaSize).run {
|
||||
metaFormat.run { readObject() }
|
||||
}
|
||||
metaFormat.readObject(input.limit(metaSize))
|
||||
} else {
|
||||
error("Can't partially read an envelope with undefined meta size")
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
//returning an Envelope without data if end of input is reached
|
||||
} while (!line.startsWith(dataStart))
|
||||
@ -168,26 +174,26 @@ class TaglessEnvelopeFormat(
|
||||
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"
|
||||
const val META_LENGTH_PROPERTY = "metaLength"
|
||||
const val DATA_LENGTH_PROPERTY = "dataLength"
|
||||
public const val META_TYPE_PROPERTY: String = "metaType"
|
||||
public const val META_LENGTH_PROPERTY: String = "metaLength"
|
||||
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~#"
|
||||
const val META_START_PROPERTY = "metaSeparator"
|
||||
const val DEFAULT_META_START = "#~META~#"
|
||||
const val DATA_START_PROPERTY = "dataSeparator"
|
||||
const val DEFAULT_DATA_START = "#~DATA~#"
|
||||
public const val TAGLESS_ENVELOPE_HEADER: String = "#~DFTL~#"
|
||||
public const val META_START_PROPERTY: String = "metaSeparator"
|
||||
public const val DEFAULT_META_START: String = "#~META~#"
|
||||
public const val DATA_START_PROPERTY: String = "dataSeparator"
|
||||
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 {
|
||||
return TaglessEnvelopeFormat(context.io, meta)
|
||||
@ -195,14 +201,24 @@ class TaglessEnvelopeFormat(
|
||||
|
||||
private val default by lazy { invoke() }
|
||||
|
||||
override fun Input.readPartial(): PartialEnvelope =
|
||||
default.run { readPartial() }
|
||||
override fun readPartial(input: Input): PartialEnvelope =
|
||||
default.run { readPartial(input) }
|
||||
|
||||
override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta) =
|
||||
default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) }
|
||||
override fun writeEnvelope(
|
||||
output: Output,
|
||||
envelope: Envelope,
|
||||
metaFormatFactory: MetaFormatFactory,
|
||||
formatMeta: Meta,
|
||||
): Unit = default.run {
|
||||
writeEnvelope(
|
||||
output,
|
||||
envelope,
|
||||
metaFormatFactory,
|
||||
formatMeta
|
||||
)
|
||||
}
|
||||
|
||||
override fun Input.readObject(): Envelope =
|
||||
default.run { readObject() }
|
||||
override fun readObject(input: Input): Envelope = default.readObject(input)
|
||||
|
||||
override fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat? {
|
||||
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 kotlin.math.min
|
||||
|
||||
fun Output.writeRawString(str: String) {
|
||||
public fun Output.writeRawString(str: String) {
|
||||
str.forEach { writeByte(it.toByte()) }
|
||||
}
|
||||
|
||||
fun Input.readRawString(size: Int): String {
|
||||
public fun Input.readRawString(size: Int): String {
|
||||
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()
|
||||
|
||||
@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()
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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
|
||||
fun testTaggedFormat(){
|
||||
TaggedEnvelopeFormat.run {
|
||||
val byteArray = this.toByteArray(envelope)
|
||||
val byteArray = writeToByteArray(envelope)
|
||||
//println(byteArray.decodeToString())
|
||||
val res = readByteArray(byteArray)
|
||||
val res = readFromByteArray(byteArray)
|
||||
assertEquals(envelope.meta,res.meta)
|
||||
val double = res.data?.read {
|
||||
readDouble()
|
||||
@ -37,9 +37,9 @@ class EnvelopeFormatTest {
|
||||
@Test
|
||||
fun testTaglessFormat(){
|
||||
TaglessEnvelopeFormat.run {
|
||||
val byteArray = toByteArray(envelope)
|
||||
val byteArray = writeToByteArray(envelope)
|
||||
//println(byteArray.decodeToString())
|
||||
val res = readByteArray(byteArray)
|
||||
val res = readFromByteArray(byteArray)
|
||||
assertEquals(envelope.meta,res.meta)
|
||||
val double = res.data?.read {
|
||||
readDouble()
|
||||
|
@ -3,18 +3,16 @@ package hep.dataforge.io
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
||||
import kotlinx.io.asBinary
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun Meta.toByteArray(format: MetaFormat = JsonMetaFormat) = buildByteArray {
|
||||
format.run { writeObject(this@toByteArray) }
|
||||
format.writeObject(this@buildByteArray, this@toByteArray)
|
||||
}
|
||||
|
||||
fun MetaFormat.fromByteArray(packet: ByteArray): Meta {
|
||||
return packet.asBinary().read { readObject() }
|
||||
return packet.asBinary().read { readObject(this) }
|
||||
}
|
||||
|
||||
class MetaFormatTest {
|
||||
@ -57,21 +55,21 @@ class MetaFormatTest {
|
||||
|
||||
@Test
|
||||
fun testJsonToMeta() {
|
||||
val json = jsonArray {
|
||||
val json = buildJsonArray {
|
||||
//top level array
|
||||
+jsonArray {
|
||||
+JsonPrimitive(88)
|
||||
+json {
|
||||
"c" to "aasdad"
|
||||
"d" to true
|
||||
}
|
||||
}
|
||||
+"value"
|
||||
+jsonArray {
|
||||
+JsonPrimitive(1.0)
|
||||
+JsonPrimitive(2.0)
|
||||
+JsonPrimitive(3.0)
|
||||
}
|
||||
add(buildJsonArray {
|
||||
add(JsonPrimitive(88))
|
||||
add(buildJsonObject {
|
||||
put("c", "aasdad")
|
||||
put("d", true)
|
||||
})
|
||||
})
|
||||
add("value")
|
||||
add(buildJsonArray {
|
||||
add(JsonPrimitive(1.0))
|
||||
add(JsonPrimitive(2.0))
|
||||
add(JsonPrimitive(3.0))
|
||||
})
|
||||
}
|
||||
val meta = json.toMetaItem().node!!
|
||||
|
||||
|
@ -1,12 +1,19 @@
|
||||
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.toName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
val JSON_PRETTY: Json = Json { prettyPrint = true; useArrayPolymorphism = true }
|
||||
val JSON_PLAIN: Json = Json { prettyPrint = false; useArrayPolymorphism = true }
|
||||
|
||||
class MetaSerializerTest {
|
||||
val meta = Meta {
|
||||
"a" put 22
|
||||
@ -19,29 +26,33 @@ class MetaSerializerTest {
|
||||
|
||||
@Test
|
||||
fun testMetaSerialization() {
|
||||
val string = JSON_PRETTY.stringify(MetaSerializer, meta)
|
||||
val restored = JSON_PLAIN.parse(MetaSerializer, string)
|
||||
assertEquals(restored, meta)
|
||||
val string = JSON_PRETTY.encodeToString(MetaSerializer, meta)
|
||||
println(string)
|
||||
val restored = JSON_PLAIN.decodeFromString(MetaSerializer, string)
|
||||
assertEquals(meta, restored)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Test
|
||||
fun testCborSerialization() {
|
||||
val bytes = Cbor.dump(MetaSerializer, meta)
|
||||
println(bytes.contentToString())
|
||||
val restored = Cbor.load(MetaSerializer, bytes)
|
||||
assertEquals(restored, meta)
|
||||
val bytes = Cbor.encodeToByteArray(MetaSerializer, meta)
|
||||
println(bytes.decodeToString())
|
||||
val restored = Cbor.decodeFromByteArray(MetaSerializer, bytes)
|
||||
assertEquals(meta, restored)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNameSerialization() {
|
||||
val name = "a.b.c".toName()
|
||||
val string = JSON_PRETTY.stringify(Name.serializer(), name)
|
||||
val restored = JSON_PLAIN.parse(Name.serializer(), string)
|
||||
assertEquals(restored, name)
|
||||
val string = JSON_PRETTY.encodeToString(Name.serializer(), name)
|
||||
val restored = JSON_PLAIN.decodeFromString(Name.serializer(), string)
|
||||
assertEquals(name, restored)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Test
|
||||
fun testMetaItemDescriptor() {
|
||||
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.use
|
||||
|
||||
fun <T : Any> IOFormat<T>.toByteArray(obj: T): ByteArray = buildByteArray { writeObject(obj) }
|
||||
fun <T : Any> IOFormat<T>.readByteArray(array: ByteArray): T = ByteArrayInput(array).use { it.readObject() }
|
||||
fun <T : Any> IOFormat<T>.writeToByteArray(obj: T): ByteArray = buildByteArray { writeObject(this, obj) }
|
||||
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.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
|
||||
*/
|
||||
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)
|
||||
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]
|
||||
*/
|
||||
fun Path.append(block: Output.() -> Unit): Unit {
|
||||
public fun Path.append(block: Output.() -> Unit): Unit {
|
||||
val stream = Files.newOutputStream(
|
||||
this,
|
||||
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]
|
||||
*/
|
||||
fun Path.rewrite(block: Output.() -> Unit): Unit {
|
||||
public fun Path.rewrite(block: Output.() -> Unit): Unit {
|
||||
val stream = Files.newOutputStream(
|
||||
this,
|
||||
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE
|
||||
@ -43,9 +43,9 @@ fun Path.rewrite(block: Output.() -> Unit): Unit {
|
||||
stream.asOutput().use(block)
|
||||
}
|
||||
|
||||
fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
||||
public fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
||||
val partialEnvelope: PartialEnvelope = asBinary().read {
|
||||
format.run { readPartial() }
|
||||
format.run { readPartial(this@read) }
|
||||
}
|
||||
val offset: Int = partialEnvelope.dataOffset.toInt()
|
||||
val size: Int = partialEnvelope.dataSize?.toInt() ?: (Files.size(this).toInt() - offset)
|
||||
@ -58,7 +58,7 @@ fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@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>?
|
||||
}
|
||||
|
||||
@ -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.
|
||||
* 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")
|
||||
|
||||
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")
|
||||
return metaFormat.run {
|
||||
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].
|
||||
* Like "meta.json"
|
||||
*/
|
||||
fun IOPlugin.writeMetaFile(
|
||||
public fun IOPlugin.writeMetaFile(
|
||||
path: Path,
|
||||
meta: Meta,
|
||||
metaFormat: MetaFormatFactory = JsonMetaFormat,
|
||||
descriptor: NodeDescriptor? = null
|
||||
descriptor: NodeDescriptor? = null,
|
||||
) {
|
||||
val actualPath = if (Files.isDirectory(path)) {
|
||||
path.resolve("@" + metaFormat.name.toString())
|
||||
@ -102,7 +106,7 @@ fun IOPlugin.writeMetaFile(
|
||||
}
|
||||
metaFormat.run {
|
||||
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
|
||||
* 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 formats = envelopeFormatFactories.mapNotNull { factory ->
|
||||
binary.read {
|
||||
@ -126,8 +130,8 @@ fun IOPlugin.peekBinaryFormat(path: Path): EnvelopeFormat? {
|
||||
}
|
||||
}
|
||||
|
||||
val IOPlugin.Companion.META_FILE_NAME: String get() = "@meta"
|
||||
val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
|
||||
public val IOPlugin.Companion.META_FILE_NAME: String get() = "@meta"
|
||||
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.
|
||||
@ -143,17 +147,18 @@ val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
|
||||
* Return null otherwise.
|
||||
*/
|
||||
@DFExperimental
|
||||
fun IOPlugin.readEnvelopeFile(
|
||||
public fun IOPlugin.readEnvelopeFile(
|
||||
path: Path,
|
||||
readNonEnvelopes: Boolean = false,
|
||||
formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat
|
||||
formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat,
|
||||
): Envelope? {
|
||||
if (!Files.exists(path)) return null
|
||||
|
||||
//read two-files directory
|
||||
if (Files.isDirectory(path)) {
|
||||
val metaFile = Files.list(path).asSequence()
|
||||
.singleOrNull { it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME) }
|
||||
val metaFile = Files.list(path).asSequence().singleOrNull {
|
||||
it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME)
|
||||
}
|
||||
|
||||
val meta = if (metaFile == null) {
|
||||
Meta.EMPTY
|
||||
@ -182,9 +187,9 @@ fun IOPlugin.readEnvelopeFile(
|
||||
/**
|
||||
* 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 {
|
||||
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]
|
||||
*/
|
||||
@DFExperimental
|
||||
fun IOPlugin.writeEnvelopeFile(
|
||||
public fun IOPlugin.writeEnvelopeFile(
|
||||
path: Path,
|
||||
envelope: Envelope,
|
||||
envelopeFormat: EnvelopeFormat = TaggedEnvelopeFormat,
|
||||
metaFormat: MetaFormatFactory? = null
|
||||
metaFormat: MetaFormatFactory? = null,
|
||||
) {
|
||||
path.rewrite {
|
||||
with(envelopeFormat) {
|
||||
writeEnvelope(envelope, metaFormat ?: envelopeFormat.defaultMetaFormat)
|
||||
}
|
||||
envelopeFormat.writeEnvelope(this, envelope, metaFormat ?: envelopeFormat.defaultMetaFormat)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,10 +212,10 @@ fun IOPlugin.writeEnvelopeFile(
|
||||
* Write separate meta and data files to given directory [path]
|
||||
*/
|
||||
@DFExperimental
|
||||
fun IOPlugin.writeEnvelopeDirectory(
|
||||
public fun IOPlugin.writeEnvelopeDirectory(
|
||||
path: Path,
|
||||
envelope: Envelope,
|
||||
metaFormat: MetaFormatFactory = JsonMetaFormat
|
||||
metaFormat: MetaFormatFactory = JsonMetaFormat,
|
||||
) {
|
||||
if (!Files.exists(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.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)
|
||||
read(buffer)
|
||||
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()
|
||||
}
|
@ -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 {
|
||||
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"
|
@ -4,25 +4,30 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
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
|
||||
|
||||
data class MetaListener(
|
||||
public data class MetaListener(
|
||||
val owner: Any? = null,
|
||||
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
|
||||
)
|
||||
|
||||
interface ObservableMeta : Meta {
|
||||
fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
|
||||
fun removeListener(owner: Any?)
|
||||
public interface ObservableMeta : Meta {
|
||||
public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
|
||||
public fun removeListener(owner: Any?)
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable meta representing object state
|
||||
*/
|
||||
@Serializable
|
||||
class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
||||
@Serializable(Config.Companion::class)
|
||||
public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
|
||||
|
||||
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>?) {
|
||||
if (newItem == null) {
|
||||
_items.remove(key)
|
||||
children.remove(key)
|
||||
if (oldItem != null && oldItem is MetaItem.NodeItem<Config>) {
|
||||
oldItem.node.removeListener(this)
|
||||
}
|
||||
} else {
|
||||
_items[key] = newItem
|
||||
children[key] = newItem
|
||||
if (newItem is MetaItem.NodeItem) {
|
||||
newItem.node.onChange(this) { name, oldChild, newChild ->
|
||||
itemChanged(key + name, oldChild, newChild)
|
||||
@ -68,10 +73,9 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
||||
|
||||
override fun empty(): Config = Config()
|
||||
|
||||
@Serializer(Config::class)
|
||||
companion object ConfigSerializer : KSerializer<Config> {
|
||||
public companion object ConfigSerializer : KSerializer<Config> {
|
||||
|
||||
fun empty(): Config = Config()
|
||||
public fun empty(): Config = Config()
|
||||
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
|
||||
|
||||
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 ->
|
||||
val item = entry.value
|
||||
builder[entry.key.asName()] = when (item) {
|
||||
|
@ -1,115 +1,24 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.meta.descriptors.*
|
||||
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.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A container that holds a [Config] and a default item provider.
|
||||
* 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.
|
||||
* A container that holds a [Config].
|
||||
*/
|
||||
interface Configurable : Described, MutableItemProvider {
|
||||
public interface Configurable {
|
||||
/**
|
||||
* Backing config
|
||||
*/
|
||||
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")
|
||||
}
|
||||
}
|
||||
public val config: Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the property to its default value
|
||||
*/
|
||||
fun Configurable.resetProperty(name: Name) {
|
||||
setItem(name, null)
|
||||
}
|
||||
|
||||
fun Configurable.getItem(key: String) = getItem(key.toName())
|
||||
|
||||
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) }
|
||||
public fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
|
||||
|
||||
@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 */
|
||||
|
||||
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> =
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
public fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> = config.node(key)
|
||||
|
@ -5,62 +5,107 @@ import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.values.Value
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/* Meta delegates */
|
||||
|
||||
open class ItemDelegate(
|
||||
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
|
||||
}
|
||||
}
|
||||
public typealias ItemDelegate = ReadOnlyProperty<Any?, MetaItem<*>?>
|
||||
|
||||
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
|
||||
|
||||
|
||||
//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
|
||||
*/
|
||||
fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> =
|
||||
public fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, 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)
|
||||
|
||||
fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> =
|
||||
public fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, 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)
|
||||
|
||||
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)
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
@ -4,6 +4,7 @@ package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
|
||||
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.ValueDescriptor
|
||||
import hep.dataforge.names.NameToken
|
||||
@ -15,7 +16,7 @@ import kotlinx.serialization.json.*
|
||||
/**
|
||||
* @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()) {
|
||||
JsonArray(list.map { it.toJson() })
|
||||
} else {
|
||||
@ -52,7 +53,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
||||
fun addElement(key: String) {
|
||||
val itemDescriptor = descriptor?.items?.get(key)
|
||||
val jsonKey = key.toJsonKey(itemDescriptor)
|
||||
val items: Map<String, MetaItem<*>> = getIndexed(key)
|
||||
val items: Map<String?, MetaItem<*>> = getIndexed(key)
|
||||
when (items.size) {
|
||||
0 -> {
|
||||
//do nothing
|
||||
@ -61,9 +62,9 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
||||
elementMap[jsonKey] = items.values.first().toJsonElement(itemDescriptor, null)
|
||||
}
|
||||
else -> {
|
||||
val array = jsonArray {
|
||||
val array = buildJsonArray {
|
||||
items.forEach { (index, item) ->
|
||||
+item.toJsonElement(itemDescriptor, index)
|
||||
add(item.toJsonElement(itemDescriptor, index))
|
||||
}
|
||||
}
|
||||
elementMap[jsonKey] = array
|
||||
@ -75,32 +76,31 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
||||
|
||||
|
||||
if (indexValue != null) {
|
||||
val indexKey = descriptor?.indexKey ?: NodeDescriptor.DEFAULT_INDEX_KEY
|
||||
val indexKey = descriptor?.indexKey ?: DEFAULT_INDEX_KEY
|
||||
elementMap[indexKey] = JsonPrimitive(indexValue)
|
||||
}
|
||||
|
||||
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) {
|
||||
JsonNull -> Null
|
||||
is JsonLiteral -> {
|
||||
when (body) {
|
||||
true -> True
|
||||
false -> False
|
||||
is Number -> NumberValue(body as Number)
|
||||
else -> StringValue(content)
|
||||
else -> {
|
||||
if (isString) {
|
||||
StringValue(content)
|
||||
} else {
|
||||
content.parseValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
|
||||
public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
|
||||
is JsonPrimitive -> {
|
||||
val value = this.toValue(descriptor as? ValueDescriptor)
|
||||
MetaItem.ValueItem(value)
|
||||
@ -122,7 +122,7 @@ fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMet
|
||||
MetaItem.ValueItem(value)
|
||||
} else {
|
||||
//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
|
||||
*/
|
||||
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>> {
|
||||
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)
|
||||
} 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)
|
||||
?.get(indexKey)?.contentOrNull
|
||||
?.get(indexKey)?.jsonPrimitive?.contentOrNull
|
||||
?: index.toString() //In case index is non-string, the backward transformation will be broken.
|
||||
|
||||
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)
|
||||
|
||||
companion object{
|
||||
public companion object {
|
||||
/**
|
||||
* 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].
|
||||
* 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) {
|
||||
it.layers
|
||||
} 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 {
|
||||
layers.map { it.items.keys }.flatten().associateWith { key ->
|
||||
layers.asSequence().map { it.items[key] }.filterNotNull().let(replaceRule)
|
||||
@ -28,21 +26,21 @@ class Laminate(layers: List<Meta>) : MetaBase() {
|
||||
/**
|
||||
* Generate sealed meta using [mergeRule]
|
||||
*/
|
||||
fun merge(): SealedMeta {
|
||||
public fun merge(): SealedMeta {
|
||||
val items = layers.map { it.items.keys }.flatten().associateWith { key ->
|
||||
layers.asSequence().map { it.items[key] }.filterNotNull().merge()
|
||||
}
|
||||
return SealedMeta(items)
|
||||
}
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
|
||||
/**
|
||||
* The default rule which always uses the first found item in sequence alongside with its children.
|
||||
*
|
||||
* 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> {
|
||||
return when {
|
||||
@ -76,14 +74,17 @@ class Laminate(layers: List<Meta>) : MetaBase() {
|
||||
* The values a replaced but meta children are joined
|
||||
* 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
|
||||
*/
|
||||
fun Laminate.getFirst(name: Name): MetaItem<*>? {
|
||||
public fun Laminate.getFirst(name: Name): MetaItem<*>? {
|
||||
layers.forEach { layer ->
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
|
@ -4,8 +4,12 @@ import hep.dataforge.meta.Meta.Companion.VALUE_KEY
|
||||
import hep.dataforge.meta.MetaItem.NodeItem
|
||||
import hep.dataforge.meta.MetaItem.ValueItem
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.values.*
|
||||
import kotlinx.serialization.*
|
||||
import hep.dataforge.values.EnumValue
|
||||
import hep.dataforge.values.Null
|
||||
import hep.dataforge.values.Value
|
||||
import hep.dataforge.values.boolean
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
/**
|
||||
@ -13,28 +17,17 @@ import kotlinx.serialization.*
|
||||
* * a [ValueItem] (leaf)
|
||||
* * a [NodeItem] (node)
|
||||
*/
|
||||
@Serializable
|
||||
sealed class MetaItem<out M : Meta> {
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public sealed class MetaItem<out M : Meta>() {
|
||||
|
||||
abstract override fun equals(other: Any?): Boolean
|
||||
|
||||
abstract override fun hashCode(): Int
|
||||
|
||||
@Serializable
|
||||
class ValueItem(val value: Value) : MetaItem<Nothing>() {
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
|
||||
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 {
|
||||
return this.value == (other as? ValueItem)?.value
|
||||
}
|
||||
@ -44,29 +37,18 @@ sealed class MetaItem<out M : Meta> {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) val node: M) : MetaItem<M>() {
|
||||
@Serializable(MetaItemSerializer::class)
|
||||
public class NodeItem<M : Meta>(public val node: M) : MetaItem<M>() {
|
||||
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable
|
||||
override fun toString(): String = node.toString()
|
||||
|
||||
@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 hashCode(): Int = node.hashCode()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun of(arg: Any?): MetaItem<*> {
|
||||
public companion object {
|
||||
public fun of(arg: Any?): MetaItem<*> {
|
||||
return when (arg) {
|
||||
null -> ValueItem(Null)
|
||||
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.
|
||||
* Meaning that two states with the same meta are equal.
|
||||
*/
|
||||
interface MetaRepr {
|
||||
fun toMeta(): Meta
|
||||
@Serializable(MetaSerializer::class)
|
||||
public interface MetaRepr {
|
||||
public fun toMeta(): Meta
|
||||
}
|
||||
|
||||
interface ItemProvider{
|
||||
fun getItem(name: Name): MetaItem<*>?
|
||||
public fun interface ItemProvider {
|
||||
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
|
||||
*/
|
||||
interface Meta : MetaRepr, ItemProvider {
|
||||
public interface Meta : MetaRepr, ItemProvider {
|
||||
/**
|
||||
* Top level items of meta tree
|
||||
*/
|
||||
val items: Map<NameToken, MetaItem<*>>
|
||||
public val items: Map<NameToken, MetaItem<*>>
|
||||
|
||||
override fun getItem(name: Name): MetaItem<*>? {
|
||||
if (name.isEmpty()) return NodeItem(this)
|
||||
return name.first()?.let { token ->
|
||||
return name.firstOrNull()?.let { token ->
|
||||
val tail = name.cutFirst()
|
||||
when (tail.length) {
|
||||
0 -> items[token]
|
||||
@ -121,15 +111,15 @@ interface Meta : MetaRepr, ItemProvider {
|
||||
|
||||
override fun toString(): String
|
||||
|
||||
companion object {
|
||||
const val TYPE = "meta"
|
||||
public companion object {
|
||||
public const val TYPE: String = "meta"
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
@ -142,19 +132,19 @@ interface Meta : MetaRepr, ItemProvider {
|
||||
*
|
||||
* 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]
|
||||
*/
|
||||
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
|
||||
*/
|
||||
fun Meta.values(): Sequence<Pair<Name, Value>> {
|
||||
public fun Meta.values(): Sequence<Pair<Name, Value>> {
|
||||
return items.asSequence().flatMap { (key, item) ->
|
||||
when (item) {
|
||||
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
|
||||
*/
|
||||
fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
|
||||
public fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
|
||||
return sequence {
|
||||
items.forEach { (key, 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
|
||||
*/
|
||||
interface MetaNode<out M : MetaNode<M>> : Meta {
|
||||
public interface MetaNode<out M : MetaNode<M>> : Meta {
|
||||
override val items: Map<NameToken, MetaItem<M>>
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as [Meta.get], but with specific node type
|
||||
*/
|
||||
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
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
|
||||
(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
|
||||
*/
|
||||
abstract class MetaBase : Meta {
|
||||
public abstract class MetaBase : Meta {
|
||||
|
||||
override fun equals(other: Any?): Boolean = if (other is Meta) {
|
||||
this.items == other.items
|
||||
@ -215,30 +205,33 @@ abstract class MetaBase : Meta {
|
||||
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* If the argument is possibly mutable node, it is copied on creation
|
||||
*/
|
||||
class SealedMeta internal constructor(
|
||||
override val items: Map<NameToken, MetaItem<SealedMeta>>
|
||||
public class SealedMeta internal constructor(
|
||||
override val items: Map<NameToken, MetaItem<SealedMeta>>,
|
||||
) : AbstractMetaNode<SealedMeta>()
|
||||
|
||||
/**
|
||||
* Generate sealed node from [this]. If it is already sealed return it as is
|
||||
*/
|
||||
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")
|
||||
fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
||||
public fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
||||
is ValueItem -> this
|
||||
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]
|
||||
*/
|
||||
val MetaItem<*>?.value: Value?
|
||||
public val MetaItem<*>?.value: Value?
|
||||
get() = (this as? ValueItem)?.value
|
||||
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
|
||||
|
||||
val MetaItem<*>?.string get() = value?.string
|
||||
val MetaItem<*>?.boolean get() = value?.boolean
|
||||
val MetaItem<*>?.number get() = value?.number
|
||||
val MetaItem<*>?.double get() = number?.toDouble()
|
||||
val MetaItem<*>?.float get() = number?.toFloat()
|
||||
val MetaItem<*>?.int get() = number?.toInt()
|
||||
val MetaItem<*>?.long get() = number?.toLong()
|
||||
val MetaItem<*>?.short get() = number?.toShort()
|
||||
public val MetaItem<*>?.string: String? get() = value?.string
|
||||
public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean
|
||||
public val MetaItem<*>?.number: Number? get() = value?.number
|
||||
public val MetaItem<*>?.double: Double? get() = number?.toDouble()
|
||||
public val MetaItem<*>?.float: Float? get() = number?.toFloat()
|
||||
public val MetaItem<*>?.int: Int? get() = number?.toInt()
|
||||
public val MetaItem<*>?.long: Long? get() = number?.toLong()
|
||||
public val MetaItem<*>?.short: Short? get() = number?.toShort()
|
||||
|
||||
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
|
||||
} else {
|
||||
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) {
|
||||
null -> null
|
||||
is ValueItem -> null//error("Trying to interpret value meta item as node item")
|
||||
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
|
||||
*/
|
||||
@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 empty(): MetaBuilder = MetaBuilder()
|
||||
|
||||
infix fun String.put(item: MetaItem<*>?) {
|
||||
public infix fun String.put(item: MetaItem<*>?) {
|
||||
set(this, item)
|
||||
}
|
||||
|
||||
infix fun String.put(value: Value?) {
|
||||
public infix fun String.put(value: Value?) {
|
||||
set(this, value)
|
||||
}
|
||||
|
||||
infix fun String.put(string: String?) {
|
||||
public infix fun String.put(string: String?) {
|
||||
set(this, string?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(number: Number?) {
|
||||
public infix fun String.put(number: Number?) {
|
||||
set(this, number?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(boolean: Boolean?) {
|
||||
public infix fun String.put(boolean: Boolean?) {
|
||||
set(this, boolean?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(enum: Enum<*>) {
|
||||
public infix fun String.put(enum: Enum<*>) {
|
||||
set(this, EnumValue(enum))
|
||||
}
|
||||
|
||||
@JvmName("putValues")
|
||||
infix fun String.put(iterable: Iterable<Value>) {
|
||||
public infix fun String.put(iterable: Iterable<Value>) {
|
||||
set(this, iterable.asValue())
|
||||
}
|
||||
|
||||
@JvmName("putNumbers")
|
||||
infix fun String.put(iterable: Iterable<Number>) {
|
||||
public infix fun String.put(iterable: Iterable<Number>) {
|
||||
set(this, iterable.map { it.asValue() }.asValue())
|
||||
}
|
||||
|
||||
@JvmName("putStrings")
|
||||
infix fun String.put(iterable: Iterable<String>) {
|
||||
public infix fun String.put(iterable: Iterable<String>) {
|
||||
set(this, iterable.map { it.asValue() }.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(array: DoubleArray) {
|
||||
public infix fun String.put(array: DoubleArray) {
|
||||
set(this, array.asValue())
|
||||
}
|
||||
|
||||
infix fun String.putValue(any: Any?) {
|
||||
set(this, Value.of(any))
|
||||
}
|
||||
|
||||
infix fun String.put(meta: Meta?) {
|
||||
public infix fun String.put(meta: Meta?) {
|
||||
this@MetaBuilder[this] = meta
|
||||
}
|
||||
|
||||
infix fun String.put(repr: MetaRepr?) {
|
||||
public infix fun String.put(repr: MetaRepr?) {
|
||||
set(this, repr?.toMeta())
|
||||
}
|
||||
|
||||
@JvmName("putMetas")
|
||||
infix fun String.put(value: Iterable<Meta>) {
|
||||
this@MetaBuilder[this] = value.toList()
|
||||
public infix fun String.put(value: Iterable<Meta>) {
|
||||
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)
|
||||
}
|
||||
|
||||
infix fun Name.put(value: Value?) {
|
||||
public infix fun Name.put(value: Value?) {
|
||||
set(this, value)
|
||||
}
|
||||
|
||||
infix fun Name.put(string: String?) {
|
||||
public infix fun Name.put(string: String?) {
|
||||
set(this, string?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(number: Number?) {
|
||||
public infix fun Name.put(number: Number?) {
|
||||
set(this, number?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(boolean: Boolean?) {
|
||||
public infix fun Name.put(boolean: Boolean?) {
|
||||
set(this, boolean?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(enum: Enum<*>) {
|
||||
public infix fun Name.put(enum: Enum<*>) {
|
||||
set(this, EnumValue(enum))
|
||||
}
|
||||
|
||||
@JvmName("putValues")
|
||||
infix fun Name.put(iterable: Iterable<Value>) {
|
||||
public infix fun Name.put(iterable: Iterable<Value>) {
|
||||
set(this, iterable.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(meta: Meta?) {
|
||||
public infix fun Name.put(meta: Meta?) {
|
||||
this@MetaBuilder[this] = meta
|
||||
}
|
||||
|
||||
infix fun Name.put(repr: MetaRepr?) {
|
||||
public infix fun Name.put(repr: MetaRepr?) {
|
||||
set(this, repr?.toMeta())
|
||||
}
|
||||
|
||||
@JvmName("putMetas")
|
||||
infix fun Name.put(value: Iterable<Meta>) {
|
||||
this@MetaBuilder[this] = value.toList()
|
||||
public infix fun Name.put(value: Iterable<Meta>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -125,7 +121,7 @@ class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
||||
/**
|
||||
* 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 ->
|
||||
items.mapValues { entry ->
|
||||
val item = entry.value
|
||||
@ -140,16 +136,10 @@ fun Meta.builder(): MetaBuilder {
|
||||
/**
|
||||
* Create a deep copy of this meta and apply builder to it
|
||||
*/
|
||||
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)
|
||||
public fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
|
||||
|
||||
/**
|
||||
* Build a [MetaBuilder] using given transformation
|
||||
*/
|
||||
@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
|
||||
|
||||
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.json.JsonInput
|
||||
import kotlinx.serialization.json.JsonObjectSerializer
|
||||
import kotlinx.serialization.json.JsonOutput
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
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
|
||||
*/
|
||||
@Serializer(Meta::class)
|
||||
object MetaSerializer : KSerializer<Meta> {
|
||||
private val mapSerializer = MapSerializer(
|
||||
NameToken.serializer(),
|
||||
MetaItem.serializer(MetaSerializer)
|
||||
public object MetaSerializer : KSerializer<Meta> {
|
||||
|
||||
private val mapSerializer: KSerializer<Map<NameToken, MetaItem<Meta>>> = MapSerializer(
|
||||
NameToken,
|
||||
MetaItemSerializer//MetaItem.serializer(MetaSerializer)
|
||||
)
|
||||
|
||||
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Meta {
|
||||
return if (decoder is JsonInput) {
|
||||
JsonObjectSerializer.deserialize(decoder).toMeta()
|
||||
return if (decoder is JsonDecoder) {
|
||||
JsonObject.serializer().deserialize(decoder).toMeta()
|
||||
} else {
|
||||
object : MetaBase() {
|
||||
override val items: Map<NameToken, MetaItem<*>> = mapSerializer.deserialize(decoder)
|
||||
@ -31,8 +71,8 @@ object MetaSerializer : KSerializer<Meta> {
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Meta) {
|
||||
if (encoder is JsonOutput) {
|
||||
JsonObjectSerializer.serialize(encoder, value.toJson())
|
||||
if (encoder is JsonEncoder) {
|
||||
JsonObject.serializer().serialize(encoder, value.toJson())
|
||||
} else {
|
||||
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.values.DoubleArrayValue
|
||||
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.reflect.KProperty
|
||||
|
||||
/* Read-write delegates */
|
||||
|
||||
open class MutableItemDelegate(
|
||||
override val owner: MutableItemProvider,
|
||||
key: Name? = null,
|
||||
default: MetaItem<*>? = null
|
||||
) : ItemDelegate(owner, key, default), ReadWriteProperty<Any?, MetaItem<*>?> {
|
||||
public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem<*>?>
|
||||
|
||||
public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = object : MutableItemDelegate {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
|
||||
return getItem(key ?: property.name.asName())
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>?) {
|
||||
val name = key ?: property.name.asName()
|
||||
owner.setItem(name, value)
|
||||
setItem(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate =
|
||||
MutableItemDelegate(this, key)
|
||||
/* Mutable converters */
|
||||
|
||||
//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
|
||||
*/
|
||||
fun MutableItemProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
||||
public fun MutableItemProvider.value(key: Name? = null): ReadWriteProperty<Any?, 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)
|
||||
|
||||
fun MutableItemProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
|
||||
public fun MutableItemProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, 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)
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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 }
|
||||
|
||||
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) } })
|
||||
|
||||
/* Number delegates */
|
||||
|
||||
fun <T> MutableItemProvider.item(
|
||||
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?> =
|
||||
public fun MutableItemProvider.int(key: Name? = null): ReadWriteProperty<Any?, 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)
|
||||
|
||||
fun MutableItemProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> =
|
||||
public fun MutableItemProvider.long(key: Name? = null): ReadWriteProperty<Any?, 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)
|
||||
|
||||
|
||||
/* 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 }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
/* Extra delegates for special cases */
|
||||
|
||||
fun MutableItemProvider.stringListOrNull(
|
||||
vararg strings: String,
|
||||
key: Name? = null
|
||||
): ReadWriteProperty<Any?, List<String>?> =
|
||||
item(listOf(*strings), key) {
|
||||
it?.value?.stringList
|
||||
}
|
||||
public fun MutableItemProvider.stringList(
|
||||
vararg default: String,
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<String>> = item(key).convert(
|
||||
reader = { it?.stringList ?: listOf(*default) },
|
||||
writer = { it.map { str -> str.asValue() }.asValue().asMetaItem() }
|
||||
)
|
||||
|
||||
fun MutableItemProvider.numberList(vararg numbers: Number, key: Name? = null): ReadWriteProperty<Any?, List<Number>> =
|
||||
item(listOf(*numbers), key) { item ->
|
||||
item?.value?.list?.map { it.number } ?: emptyList()
|
||||
}
|
||||
public fun MutableItemProvider.stringList(
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<String>?> = item(key).convert(
|
||||
reader = { it?.stringList },
|
||||
writer = { it?.map { str -> str.asValue() }?.asValue()?.asMetaItem() }
|
||||
)
|
||||
|
||||
/**
|
||||
* A special delegate for double arrays
|
||||
*/
|
||||
fun MutableItemProvider.doubleArray(vararg doubles: Double, key: Name? = null): ReadWriteProperty<Any?, DoubleArray> =
|
||||
item(doubleArrayOf(*doubles), key) {
|
||||
(it.value as? DoubleArrayValue)?.value
|
||||
?: it?.value?.list?.map { value -> value.number.toDouble() }?.toDoubleArray()
|
||||
?: doubleArrayOf()
|
||||
}
|
||||
public fun MutableItemProvider.numberList(
|
||||
vararg default: Number,
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
|
||||
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) },
|
||||
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
|
||||
)
|
||||
|
||||
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,
|
||||
writer: (T) -> Value = { Value.of(it) },
|
||||
reader: (Value) -> T
|
||||
reader: (Value) -> T,
|
||||
): 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
|
||||
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.values.Value
|
||||
|
||||
interface MutableItemProvider : ItemProvider {
|
||||
fun setItem(name: Name, item: MetaItem<*>?)
|
||||
}
|
||||
|
||||
interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider {
|
||||
public interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider {
|
||||
override val items: Map<NameToken, MetaItem<M>>
|
||||
// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
||||
// 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.
|
||||
*/
|
||||
abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
|
||||
protected val _items: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap()
|
||||
public abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
|
||||
protected val children: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap()
|
||||
|
||||
override val items: Map<NameToken, MetaItem<M>>
|
||||
get() = _items
|
||||
get() = children
|
||||
|
||||
//protected abstract fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?)
|
||||
|
||||
protected open fun replaceItem(key: NameToken, oldItem: MetaItem<M>?, newItem: MetaItem<M>?) {
|
||||
if (newItem == null) {
|
||||
_items.remove(key)
|
||||
children.remove(key)
|
||||
} else {
|
||||
_items[key] = newItem
|
||||
children[key] = newItem
|
||||
}
|
||||
//itemChanged(key.asName(), oldItem, newItem)
|
||||
}
|
||||
@ -56,12 +51,12 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
|
||||
when (name.length) {
|
||||
0 -> error("Can't setValue meta item for empty name")
|
||||
1 -> {
|
||||
val token = name.first()!!
|
||||
val token = name.firstOrNull()!!
|
||||
@Suppress("UNCHECKED_CAST") val oldItem: MetaItem<M>? = get(name) as? MetaItem<M>
|
||||
replaceItem(token, oldItem, wrapItem(item))
|
||||
}
|
||||
else -> {
|
||||
val token = name.first()!!
|
||||
val token = name.firstOrNull()!!
|
||||
//get existing or create new node. Query is ignored for new node
|
||||
if (items[token] == null) {
|
||||
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:
|
||||
* * value replaces anything
|
||||
* * node updates node and replaces anything but node
|
||||
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
|
||||
*/
|
||||
fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
||||
public fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
||||
meta.items.forEach { entry ->
|
||||
when (val value = entry.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
|
||||
*/
|
||||
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" }
|
||||
val newIndex = name.last()!!.index
|
||||
if (newIndex.isNotEmpty()) {
|
||||
val newIndex = name.lastOrNull()!!.index
|
||||
if (newIndex != null) {
|
||||
set(name, value)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
@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)) {
|
||||
null -> empty().also { set(name, it) }
|
||||
is MetaItem.NodeItem<M> -> existingItem.node
|
||||
|
@ -3,28 +3,54 @@ package hep.dataforge.meta
|
||||
import hep.dataforge.meta.descriptors.*
|
||||
import hep.dataforge.names.Name
|
||||
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].
|
||||
* Default item provider and [NodeDescriptor] are optional
|
||||
*/
|
||||
open class Scheme() : Configurable, Described, MetaRepr {
|
||||
constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() {
|
||||
this.config = config
|
||||
this.defaultProvider = defaultProvider
|
||||
public open class Scheme(
|
||||
config: Config = Config(),
|
||||
internal var default: ItemProvider? = null,
|
||||
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
|
||||
|
||||
override fun getDefaultItem(name: Name): MetaItem<*>? {
|
||||
return defaultProvider(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")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,56 +58,73 @@ open class Scheme() : Configurable, Described, MetaRepr {
|
||||
* values if default value is unavailable.
|
||||
* 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)
|
||||
|
||||
private inner class DefaultLayer(val path: Name) : MetaBase() {
|
||||
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()
|
||||
}
|
||||
public fun isEmpty(): Boolean = config.isEmpty()
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
open class SchemeSpec<T : Scheme>(val builder: () -> T) :
|
||||
Specification<T> {
|
||||
override fun empty(): T = builder()
|
||||
public open class SchemeSpec<T : Scheme>(
|
||||
private val builder: (config: Config, defaultProvider: ItemProvider, descriptor: NodeDescriptor?) -> T,
|
||||
) : Specification<T>, Described {
|
||||
|
||||
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T {
|
||||
return empty().apply {
|
||||
public constructor(emptyBuilder: () -> T) : this({ config: Config, defaultProvider: ItemProvider, descriptor: NodeDescriptor? ->
|
||||
emptyBuilder().apply {
|
||||
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")
|
||||
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
|
||||
*/
|
||||
open class MetaScheme(
|
||||
val meta: Meta,
|
||||
override val descriptor: NodeDescriptor? = null,
|
||||
config: Config = Config()
|
||||
) : Scheme(config, meta::get) {
|
||||
override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
|
||||
///**
|
||||
// * A scheme that uses [Meta] as a default layer
|
||||
// */
|
||||
//public open class MetaScheme(
|
||||
// private val meta: Meta,
|
||||
// override val descriptor: NodeDescriptor? = null,
|
||||
// config: Config = Config(),
|
||||
//) : Scheme(config, meta) {
|
||||
// override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
|
||||
//}
|
||||
|
||||
public fun Meta.asScheme(): Scheme = Scheme().apply {
|
||||
config = this@asScheme.asConfig()
|
||||
}
|
||||
|
||||
fun Meta.asScheme() =
|
||||
MetaScheme(this)
|
||||
|
||||
fun <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit) = spec.wrap(this).apply(block)
|
||||
public fun <T : MutableItemProvider> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit = {}): T =
|
||||
spec.read(this).apply(block)
|
||||
|
@ -1,67 +1,102 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
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.
|
||||
* By convention [Scheme] companion should inherit this class
|
||||
*
|
||||
*/
|
||||
interface Specification<T : Configurable> {
|
||||
fun empty() = wrap()
|
||||
public interface Specification<T : MutableItemProvider> {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
fun <T : Configurable> Specification<T>.update(config: Config, action: T.() -> Unit): T = wrap(config).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)
|
||||
}
|
||||
public fun <T : MutableItemProvider> Specification<T>.update(meta: Meta, action: T.() -> Unit): T =
|
||||
read(meta).apply(action)
|
||||
|
||||
|
||||
/**
|
||||
* Apply specified configuration to configurable
|
||||
*/
|
||||
fun <T : Configurable, C : Configurable, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit) =
|
||||
apply { spec.update(config, action) }
|
||||
public fun <T : MetaRepr, C : MutableItemProvider, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit): T =
|
||||
apply { spec.update(toMeta(), action) }
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
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(
|
||||
Config(), it
|
||||
)
|
||||
}
|
||||
|
||||
@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
|
||||
*/
|
||||
@DslMarker
|
||||
annotation class DFBuilder
|
||||
public annotation class DFBuilder
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@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
|
||||
*/
|
||||
interface Described {
|
||||
val descriptor: ItemDescriptor?
|
||||
public interface Described {
|
||||
public val descriptor: ItemDescriptor?
|
||||
|
||||
companion object {
|
||||
const val DESCRIPTOR_NODE = "@descriptor"
|
||||
public companion object {
|
||||
//public const val DESCRIPTOR_NODE: String = "@descriptor"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,32 +1,48 @@
|
||||
package hep.dataforge.meta.descriptors
|
||||
|
||||
import hep.dataforge.meta.Laminate
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBase
|
||||
import hep.dataforge.meta.MetaItem
|
||||
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<*>>
|
||||
get() = descriptor.items.entries.associate { entry ->
|
||||
NameToken(entry.key) to entry.value.defaultItem()
|
||||
get() = buildMap {
|
||||
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.
|
||||
*/
|
||||
fun ItemDescriptor.defaultItem(): MetaItem<*> {
|
||||
public fun ItemDescriptor.defaultItem(): MetaItem<*>? {
|
||||
return when (this) {
|
||||
is ValueDescriptor -> defaultItem()
|
||||
is NodeDescriptor -> defaultItem()
|
||||
|
@ -4,29 +4,26 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.values.*
|
||||
|
||||
/**
|
||||
* A common parent for [ValueDescriptor] and [NodeDescriptor]. Describes a single [MetaItem] or a group of same-name-siblings.
|
||||
*/
|
||||
@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
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
var multiple: Boolean by config.boolean(false)
|
||||
public var multiple: Boolean by config.boolean(false)
|
||||
|
||||
/**
|
||||
* The item description
|
||||
*
|
||||
* @return
|
||||
* The item description text
|
||||
*/
|
||||
var info: String? by config.string()
|
||||
public var info: String? by config.string()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
var attributes by config.node()
|
||||
}
|
||||
public var attributes: Config? by config.node()
|
||||
|
||||
/**
|
||||
* Configure attributes of the descriptor
|
||||
*/
|
||||
fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
||||
(attributes ?: Config().also { this.attributes = it }).apply(block)
|
||||
}
|
||||
/**
|
||||
* An index field by which this node is identified in case of same name siblings construct
|
||||
*/
|
||||
public var indexKey: String by config.string(DEFAULT_INDEX_KEY)
|
||||
|
||||
/**
|
||||
* Set specific attribute in the descriptor
|
||||
*/
|
||||
fun ItemDescriptor.setAttribute(name: Name, value: Any?) {
|
||||
attributes {
|
||||
set(name, value)
|
||||
public companion object{
|
||||
public const val DEFAULT_INDEX_KEY: String = "@index"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
||||
public fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
||||
if (item == null) return !required
|
||||
return when (this) {
|
||||
is ValueDescriptor -> isAllowedValue(item.value ?: return false)
|
||||
@ -73,7 +70,7 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
public class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
init {
|
||||
config[IS_NODE_KEY] = true
|
||||
}
|
||||
@ -90,14 +87,12 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
*
|
||||
* @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)
|
||||
|
||||
val items: Map<String, ItemDescriptor>
|
||||
public val items: Map<String, ItemDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
if (node[IS_NODE_KEY].boolean == true) {
|
||||
@ -111,7 +106,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
* The map of children node descriptors
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val nodes: Map<String, NodeDescriptor>
|
||||
public val nodes: Map<String, NodeDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||
it.value.node[IS_NODE_KEY].boolean == true
|
||||
}.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 {
|
||||
it.value.node[IS_NODE_KEY].boolean != true
|
||||
}.associate { (name, item) ->
|
||||
@ -141,7 +136,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(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
|
||||
}
|
||||
|
||||
fun item(name: Name, descriptor: ItemDescriptor) {
|
||||
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
|
||||
public fun item(name: Name, descriptor: ItemDescriptor) {
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
||||
public fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
||||
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" }
|
||||
item(name, ValueDescriptor().apply(block))
|
||||
}
|
||||
|
||||
fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
||||
public fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
||||
value(name.toName(), block)
|
||||
}
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
|
||||
val ITEM_KEY = "item".asName()
|
||||
val IS_NODE_KEY = "@isNode".asName()
|
||||
internal val ITEM_KEY: Name = "item".asName()
|
||||
internal val IS_NODE_KEY: Name = "@isNode".asName()
|
||||
|
||||
const val DEFAULT_INDEX_KEY = "@index"
|
||||
|
||||
inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block)
|
||||
public inline operator fun invoke(block: NodeDescriptor.() -> Unit): NodeDescriptor = NodeDescriptor().apply(block)
|
||||
|
||||
//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
|
||||
*/
|
||||
operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
||||
public operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
||||
if (name.isEmpty()) return this
|
||||
return when (this) {
|
||||
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
|
||||
@ -213,7 +212,7 @@ operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
public class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
|
||||
/**
|
||||
* True if the value is required
|
||||
@ -227,9 +226,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
*
|
||||
* @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)
|
||||
}
|
||||
|
||||
@ -238,9 +237,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
*
|
||||
* @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)
|
||||
}
|
||||
|
||||
@ -251,7 +250,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
fun isAllowedValue(value: Value): Boolean {
|
||||
public fun isAllowedValue(value: Value): Boolean {
|
||||
return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
||||
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
||||
}
|
||||
@ -262,7 +261,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
var allowedValues: List<Value> by config.item().convert(
|
||||
public var allowedValues: List<Value> by config.item().convert(
|
||||
reader = {
|
||||
val value = it.value
|
||||
when {
|
||||
@ -279,7 +278,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
/**
|
||||
* 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) }
|
||||
}
|
||||
}
|
||||
@ -287,7 +286,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
/**
|
||||
* 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 {
|
||||
config.update(other.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
|
||||
*/
|
||||
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) ->
|
||||
token.toString() to when (item) {
|
||||
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.
|
||||
*/
|
||||
@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")
|
||||
fun toItem(value: Any?): MetaItem<*> = when (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