From 8b1d5eb69edf3e97d0987a5b470c9c75529da592 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 29 Dec 2020 22:19:11 +0300 Subject: [PATCH] Task and data input validation moved to JVM --- dataforge-context/api/dataforge-context.api | 4 - .../kotlin/hep/dataforge/context/Plugin.kt | 2 +- .../hep/dataforge/context/PluginFactory.kt | 2 +- .../kotlin/hep/dataforge/provider/dfType.kt | 1 + dataforge-data/api/dataforge-data.api | 89 +++++---- .../kotlin/hep/dataforge/data/Data.kt | 48 ++--- .../kotlin/hep/dataforge/data/DataNode.kt | 176 ++---------------- .../hep/dataforge/data/DataTreeBuilder.kt | 164 ++++++++++++++++ .../kotlin/hep/dataforge/data/Goal.kt | 49 ++--- .../kotlin/hep/dataforge/data/MapAction.kt | 47 +++-- .../kotlin/hep/dataforge/data/ReduceAction.kt | 30 ++- .../kotlin/hep/dataforge/data/SplitAction.kt | 25 +-- .../kotlin/hep/dataforge/data/dataCast.kt | 73 -------- .../kotlin/hep/dataforge/data/dataJS.kt | 14 -- .../kotlin/hep/dataforge/data/dataJVM.kt | 70 ++++++- .../kotlin/hep/dataforge/data/dataNative.kt | 14 -- .../kotlin/hep/dataforge/io/EnvelopeFormat.kt | 2 +- .../kotlin/hep/dataforge/io/IOFormat.kt | 2 +- .../kotlin/hep/dataforge/io/MetaFormat.kt | 2 +- dataforge-meta/api/dataforge-meta.api | 4 + .../kotlin/hep/dataforge/type}/Type.kt | 2 +- .../api/dataforge-workspace.api | 4 +- .../kotlin/hep/dataforge/workspace/Task.kt | 2 +- .../hep/dataforge/workspace/Workspace.kt | 9 +- .../hep/dataforge/workspace/TaskBuilder.kt | 64 +++---- .../dataforge/workspace/WorkspaceBuilder.kt | 9 +- .../dataforge/workspace/WorkspacePlugin.kt | 0 27 files changed, 429 insertions(+), 479 deletions(-) create mode 100644 dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataTreeBuilder.kt delete mode 100644 dataforge-data/src/commonMain/kotlin/hep/dataforge/data/dataCast.kt delete mode 100644 dataforge-data/src/jsMain/kotlin/hep/dataforge/data/dataJS.kt delete mode 100644 dataforge-data/src/nativeMain/kotlin/hep/dataforge/data/dataNative.kt rename {dataforge-context/src/commonMain/kotlin/hep/dataforge/provider => dataforge-meta/src/commonMain/kotlin/hep/dataforge/type}/Type.kt (90%) rename dataforge-workspace/src/{commonMain => jvmMain}/kotlin/hep/dataforge/workspace/TaskBuilder.kt (81%) rename dataforge-workspace/src/{commonMain => jvmMain}/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt (93%) rename dataforge-workspace/src/{commonMain => jvmMain}/kotlin/hep/dataforge/workspace/WorkspacePlugin.kt (100%) diff --git a/dataforge-context/api/dataforge-context.api b/dataforge-context/api/dataforge-context.api index b8c52285..1831f5ce 100644 --- a/dataforge-context/api/dataforge-context.api +++ b/dataforge-context/api/dataforge-context.api @@ -326,7 +326,3 @@ public final class hep/dataforge/provider/ProviderKt { 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; -} - diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Plugin.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Plugin.kt index ff0e3a0c..146f0e79 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Plugin.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Plugin.kt @@ -6,7 +6,7 @@ import hep.dataforge.meta.MetaRepr import hep.dataforge.names.Name import hep.dataforge.names.toName import hep.dataforge.provider.Provider -import hep.dataforge.provider.Type +import hep.dataforge.type.Type /** * The interface to define a Context plugin. A plugin stores all runtime features of a context. diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt index 5985a1e7..f5540b8c 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt @@ -1,6 +1,6 @@ package hep.dataforge.context -import hep.dataforge.provider.Type +import hep.dataforge.type.Type import kotlin.reflect.KClass @Type(PluginFactory.TYPE) diff --git a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/dfType.kt b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/dfType.kt index 9c08d6a8..b7b31b5e 100644 --- a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/dfType.kt +++ b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/dfType.kt @@ -4,6 +4,7 @@ import hep.dataforge.context.Context import hep.dataforge.context.gather import hep.dataforge.meta.DFExperimental import hep.dataforge.names.Name +import hep.dataforge.type.Type import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation diff --git a/dataforge-data/api/dataforge-data.api b/dataforge-data/api/dataforge-data.api index 06e99242..7b82acc4 100644 --- a/dataforge-data/api/dataforge-data.api +++ b/dataforge-data/api/dataforge-data.api @@ -26,6 +26,24 @@ public final class hep/dataforge/data/ActionKt { public static final fun then (Lhep/dataforge/data/Action;Lhep/dataforge/data/Action;)Lhep/dataforge/data/Action; } +public final class hep/dataforge/data/ComputationData : hep/dataforge/data/ComputationGoal, hep/dataforge/data/Data { + public fun (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V + public synthetic fun (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun getMeta ()Lhep/dataforge/meta/Meta; + public fun getType ()Lkotlin/reflect/KClass; + public fun toMeta ()Lhep/dataforge/meta/Meta; +} + +public class hep/dataforge/data/ComputationGoal : hep/dataforge/data/Goal { + public fun (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V + public synthetic fun (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getBlock ()Lkotlin/jvm/functions/Function2; + public fun getDependencies ()Ljava/util/Collection; + public final fun getResult ()Lkotlinx/coroutines/Deferred; + public fun reset ()V + public fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred; +} + public final class hep/dataforge/data/CoroutineMonitor : kotlin/coroutines/CoroutineContext$Element { public static final field Companion Lhep/dataforge/data/CoroutineMonitor$Companion; public fun ()V @@ -79,14 +97,6 @@ public final class hep/dataforge/data/Data$DefaultImpls { public static fun toMeta (Lhep/dataforge/data/Data;)Lhep/dataforge/meta/Meta; } -public final class hep/dataforge/data/DataCastKt { - public static final fun canCast (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Z - public static final fun cast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data; - public static final fun cast (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode; - public static final fun ensureType (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)V - public static final fun upcast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data; -} - public final class hep/dataforge/data/DataFilter : hep/dataforge/meta/Scheme { public static final field Companion Lhep/dataforge/data/DataFilter$Companion; public fun ()V @@ -129,17 +139,22 @@ public final class hep/dataforge/data/DataItem$Node : hep/dataforge/data/DataIte } public final class hep/dataforge/data/DataJVMKt { + public static final fun canCast (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Z + public static final fun cast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data; + public static final fun cast (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode; + public static final fun ensureType (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)V public static final fun filterIsInstance (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data; public static final fun filterIsInstance (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataItem; public static final fun filterIsInstance (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode; public static final fun get (Lhep/dataforge/data/Data;)Ljava/lang/Object; + public static final fun upcast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data; } public final class hep/dataforge/data/DataKt { public static final fun map (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/Data; public static synthetic fun map$default (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/Data; - public static final fun reduce (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/DynamicData; - public static synthetic fun reduce$default (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/DynamicData; + public static final fun reduce (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/ComputationData; + public static synthetic fun reduce$default (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/ComputationData; } public abstract interface class hep/dataforge/data/DataNode : hep/dataforge/meta/MetaRepr { @@ -164,27 +179,16 @@ public final class hep/dataforge/data/DataNode$DefaultImpls { } public final class hep/dataforge/data/DataNodeKt { - public static final fun asSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence; - public static final fun builder (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/DataTreeBuilder; public static final fun dataSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence; - public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/Data;)V - public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/Data;)V public static final fun filter (Lhep/dataforge/data/DataNode;Lkotlin/jvm/functions/Function2;)Lhep/dataforge/data/DataNode; public static final fun first (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/Data; public static final fun get (Lhep/dataforge/data/DataNode;Lhep/dataforge/names/Name;)Lhep/dataforge/data/DataItem; public static final fun get (Lhep/dataforge/data/DataNode;Ljava/lang/String;)Lhep/dataforge/data/DataItem; public static final fun getData (Lhep/dataforge/data/DataItem;)Lhep/dataforge/data/Data; public static final fun getNode (Lhep/dataforge/data/DataItem;)Lhep/dataforge/data/DataNode; + public static final fun itemSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence; public static final fun iterator (Lhep/dataforge/data/DataNode;)Ljava/util/Iterator; public static final fun join (Lhep/dataforge/data/DataNode;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/DataNode;)V - public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/DataNode;)V - public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V - public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V - public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V - public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)V - public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V } public final class hep/dataforge/data/DataTree : hep/dataforge/data/DataNode { @@ -214,6 +218,20 @@ public final class hep/dataforge/data/DataTreeBuilder { public final fun update (Lhep/dataforge/data/DataNode;)V } +public final class hep/dataforge/data/DataTreeBuilderKt { + public static final fun builder (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/DataTreeBuilder; + public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/Data;)V + public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/Data;)V + public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/DataNode;)V + public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/DataNode;)V + public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V + public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V + public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)V + public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V +} + public final class hep/dataforge/data/Dependencies : kotlin/coroutines/CoroutineContext$Element { public static final field Companion Lhep/dataforge/data/Dependencies$Companion; public fun (Ljava/util/Collection;)V @@ -228,24 +246,6 @@ public final class hep/dataforge/data/Dependencies : kotlin/coroutines/Coroutine public final class hep/dataforge/data/Dependencies$Companion : kotlin/coroutines/CoroutineContext$Key { } -public final class hep/dataforge/data/DynamicData : hep/dataforge/data/DynamicGoal, hep/dataforge/data/Data { - public fun (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V - public synthetic fun (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 (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V - public synthetic fun (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 (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaBuilder;)V @@ -302,8 +302,7 @@ public final class hep/dataforge/data/JoinGroup { } public final class hep/dataforge/data/MapAction : hep/dataforge/data/Action { - public fun (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V - public final fun getInputType ()Lkotlin/reflect/KClass; + public fun (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V 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 @@ -335,8 +334,7 @@ public final class hep/dataforge/data/NamedData : hep/dataforge/data/Data { } public final class hep/dataforge/data/ReduceAction : hep/dataforge/data/Action { - public fun (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V - public final fun getInputType ()Lkotlin/reflect/KClass; + public fun (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V 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 @@ -357,8 +355,7 @@ public final class hep/dataforge/data/ReduceGroupBuilder { } public final class hep/dataforge/data/SplitAction : hep/dataforge/data/Action { - public fun (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V - public final fun getInputType ()Lkotlin/reflect/KClass; + public fun (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V 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 diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Data.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Data.kt index c573aad8..43bbc5f2 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Data.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Data.kt @@ -3,6 +3,7 @@ package hep.dataforge.data import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaRepr import hep.dataforge.meta.isEmpty +import hep.dataforge.type.Type import kotlinx.coroutines.CoroutineScope import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext @@ -11,7 +12,8 @@ import kotlin.reflect.KClass /** * A data element characterized by its meta */ -public interface Data : Goal, MetaRepr{ +@Type(Data.TYPE) +public interface Data : Goal, MetaRepr { /** * Type marker for the data. The type is known before the calculation takes place so it could be checked. */ @@ -22,9 +24,9 @@ public interface Data : Goal, MetaRepr{ */ public val meta: Meta - override fun toMeta(): Meta = Meta { - "type" put (type.simpleName?:"undefined") - if(!meta.isEmpty()) { + override fun toMeta(): Meta = Meta { + "type" put (type.simpleName ?: "undefined") + if (!meta.isEmpty()) { "meta" put meta } } @@ -37,14 +39,14 @@ public interface Data : Goal, MetaRepr{ meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, dependencies: Collection> = emptyList(), - block: suspend CoroutineScope.() -> T - ): Data = DynamicData(type, meta, context, dependencies, block) + block: suspend CoroutineScope.() -> T, + ): Data = ComputationData(type, meta, context, dependencies, block) public inline operator fun invoke( meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, dependencies: Collection> = emptyList(), - noinline block: suspend CoroutineScope.() -> T + noinline block: suspend CoroutineScope.() -> T, ): Data = invoke(T::class, meta, context, dependencies, block) public operator fun invoke( @@ -53,7 +55,7 @@ public interface Data : Goal, MetaRepr{ meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, dependencies: Collection> = emptyList(), - block: suspend CoroutineScope.() -> T + block: suspend CoroutineScope.() -> T, ): Data = NamedData(name, invoke(type, meta, context, dependencies, block)) public inline operator fun invoke( @@ -61,7 +63,7 @@ public interface Data : Goal, MetaRepr{ meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, dependencies: Collection> = emptyList(), - noinline block: suspend CoroutineScope.() -> T + noinline block: suspend CoroutineScope.() -> T, ): Data = invoke(name, T::class, meta, context, dependencies, block) @@ -71,17 +73,17 @@ public interface Data : Goal, MetaRepr{ } -public class DynamicData( +public class ComputationData( override val type: KClass, override val meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, dependencies: Collection> = emptyList(), - block: suspend CoroutineScope.() -> T -) : Data, DynamicGoal(context, dependencies, block) + block: suspend CoroutineScope.() -> T, +) : Data, ComputationGoal(context, dependencies, block) public class StaticData( value: T, - override val meta: Meta = Meta.EMPTY + override val meta: Meta = Meta.EMPTY, ) : Data, StaticGoal(value) { override val type: KClass get() = value::class } @@ -92,8 +94,8 @@ public fun Data.map( outputType: KClass, coroutineContext: CoroutineContext = EmptyCoroutineContext, meta: Meta = this.meta, - block: suspend CoroutineScope.(T) -> R -): Data = DynamicData(outputType, meta, coroutineContext, listOf(this)) { + block: suspend CoroutineScope.(T) -> R, +): Data = ComputationData(outputType, meta, coroutineContext, listOf(this)) { block(await()) } @@ -104,8 +106,8 @@ public fun Data.map( public inline fun Data.map( coroutineContext: CoroutineContext = EmptyCoroutineContext, meta: Meta = this.meta, - noinline block: suspend CoroutineScope.(T) -> R -): Data = DynamicData(R::class, meta, coroutineContext, listOf(this)) { + noinline block: suspend CoroutineScope.(T) -> R, +): Data = ComputationData(R::class, meta, coroutineContext, listOf(this)) { block(await()) } @@ -115,8 +117,8 @@ public inline fun Data.map( public inline fun Collection>.reduce( coroutineContext: CoroutineContext = EmptyCoroutineContext, meta: Meta, - noinline block: suspend CoroutineScope.(Collection) -> R -): Data = DynamicData( + noinline block: suspend CoroutineScope.(Collection) -> R, +): Data = ComputationData( R::class, meta, coroutineContext, @@ -129,8 +131,8 @@ public fun Map>.reduce( outputType: KClass, coroutineContext: CoroutineContext = EmptyCoroutineContext, meta: Meta, - block: suspend CoroutineScope.(Map) -> R -): DynamicData = DynamicData( + block: suspend CoroutineScope.(Map) -> R, +): ComputationData = ComputationData( outputType, meta, coroutineContext, @@ -149,8 +151,8 @@ public fun Map>.reduce( public inline fun Map>.reduce( coroutineContext: CoroutineContext = EmptyCoroutineContext, meta: Meta, - noinline block: suspend CoroutineScope.(Map) -> R -): DynamicData = DynamicData( + noinline block: suspend CoroutineScope.(Map) -> R, +): ComputationData = ComputationData( R::class, meta, coroutineContext, diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataNode.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataNode.kt index 23fea9ef..e8625f65 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataNode.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataNode.kt @@ -2,13 +2,13 @@ package hep.dataforge.data import hep.dataforge.meta.* import hep.dataforge.names.* +import hep.dataforge.type.Type import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlin.collections.component1 import kotlin.collections.component2 -import kotlin.collections.set import kotlin.reflect.KClass public sealed class DataItem : MetaRepr { @@ -36,6 +36,7 @@ public sealed class DataItem : MetaRepr { /** * A tree-like data structure grouped into the node. All data inside the node must inherit its type */ +@Type(DataNode.TYPE) public interface DataNode : MetaRepr { /** @@ -49,6 +50,7 @@ public interface DataNode : MetaRepr { override fun toMeta(): Meta = Meta { "type" put (type.simpleName ?: "undefined") + "meta" put meta "items" put { this@DataNode.items.forEach { it.key.toString() put it.value.toMeta() @@ -64,7 +66,7 @@ public interface DataNode : MetaRepr { items.values.forEach { when (it) { is DataItem.Node<*> -> it.node.run { startAll() } - is DataItem.Leaf<*> -> it.data.run { startAsync() } + is DataItem.Leaf<*> -> it.data.run { startAsync(this@launch) } } } } @@ -98,11 +100,11 @@ public operator fun DataNode.get(name: String): DataItem? = get( /** * Sequence of all children including nodes */ -public fun DataNode.asSequence(): Sequence>> = sequence { +public fun DataNode.itemSequence(): Sequence>> = sequence { items.forEach { (head, item) -> yield(head.asName() to item) if (item is DataItem.Node) { - val subSequence = item.node.asSequence() + val subSequence = item.node.itemSequence() .map { (name, data) -> (head.asName() + name) to data } yieldAll(subSequence) } @@ -125,166 +127,6 @@ public fun DataNode.dataSequence(): Sequence>> = } } -public operator fun DataNode.iterator(): Iterator>> = asSequence().iterator() - -public class DataTree internal constructor( - override val type: KClass, - override val items: Map>, - override val meta: Meta -) : DataNode - -private sealed class DataTreeBuilderItem { - class Node(val tree: DataTreeBuilder) : DataTreeBuilderItem() - class Leaf(val value: Data) : DataTreeBuilderItem() -} - -/** - * A builder for a DataTree. - */ -@DFBuilder -public class DataTreeBuilder(public val type: KClass) { - private val map = HashMap>() - - private var meta = MetaBuilder() - - public operator fun set(token: NameToken, node: DataTreeBuilder) { - if (map.containsKey(token)) error("Tree entry with name $token is not empty") - map[token] = DataTreeBuilderItem.Node(node) - } - - public operator fun set(token: NameToken, data: Data) { - if (map.containsKey(token)) error("Tree entry with name $token is not empty") - map[token] = DataTreeBuilderItem.Leaf(data) - } - - private fun buildNode(token: NameToken): DataTreeBuilder { - return if (!map.containsKey(token)) { - DataTreeBuilder(type).also { map[token] = DataTreeBuilderItem.Node(it) } - } else { - (map[token] as? DataTreeBuilderItem.Node ?: error("The node with name $token is occupied by leaf")).tree - } - } - - private fun buildNode(name: Name): DataTreeBuilder { - return when (name.length) { - 0 -> this - 1 -> buildNode(name.firstOrNull()!!) - else -> buildNode(name.firstOrNull()!!).buildNode(name.cutFirst()) - } - } - - public operator fun set(name: Name, data: Data) { - when (name.length) { - 0 -> error("Can't add data with empty name") - 1 -> set(name.firstOrNull()!!, data) - 2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = data - } - } - - public operator fun set(name: Name, node: DataTreeBuilder) { - when (name.length) { - 0 -> error("Can't add data with empty name") - 1 -> set(name.firstOrNull()!!, node) - 2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = node - } - } - - public operator fun set(name: Name, node: DataNode): Unit = set(name, node.builder()) - - public operator fun set(name: Name, item: DataItem): Unit = when (item) { - is DataItem.Node -> set(name, item.node.builder()) - is DataItem.Leaf -> set(name, item.data) - } - - /** - * Append data to node - */ - public infix fun String.put(data: Data): Unit = set(toName(), data) - - /** - * Append node - */ - public infix fun String.put(node: DataNode): Unit = set(toName(), node) - - public infix fun String.put(item: DataItem): Unit = set(toName(), item) - - /** - * Build and append node - */ - public infix fun String.put(block: DataTreeBuilder.() -> Unit): Unit = set(toName(), DataTreeBuilder(type).apply(block)) - - - /** - * Update data with given node data and meta with node meta. - */ - public fun update(node: DataNode) { - node.dataSequence().forEach { - //TODO check if the place is occupied - this[it.first] = it.second - } - meta.update(node.meta) - } - - public fun meta(block: MetaBuilder.() -> Unit): MetaBuilder = meta.apply(block) - - public fun meta(meta: Meta) { - this.meta = meta.builder() - } - - public fun build(): DataTree { - val resMap = map.mapValues { (_, value) -> - when (value) { - is DataTreeBuilderItem.Leaf -> DataItem.Leaf(value.value) - is DataTreeBuilderItem.Node -> DataItem.Node(value.tree.build()) - } - } - return DataTree(type, resMap, meta.seal()) - } -} - -public fun DataTreeBuilder.datum(name: Name, data: Data) { - this[name] = data -} - -public fun DataTreeBuilder.datum(name: String, data: Data) { - this[name.toName()] = data -} - -public fun DataTreeBuilder.static(name: Name, data: T, meta: Meta = Meta.EMPTY) { - this[name] = Data.static(data, meta) -} - -public fun DataTreeBuilder.static(name: Name, data: T, block: MetaBuilder.() -> Unit = {}) { - this[name] = Data.static(data, Meta(block)) -} - -public fun DataTreeBuilder.static(name: String, data: T, block: MetaBuilder.() -> Unit = {}) { - this[name.toName()] = Data.static(data, Meta(block)) -} - -public fun DataTreeBuilder.node(name: Name, node: DataNode) { - this[name] = node -} - -public fun DataTreeBuilder.node(name: String, node: DataNode) { - this[name.toName()] = node -} - -public inline fun DataTreeBuilder.node(name: Name, noinline block: DataTreeBuilder.() -> Unit) { - this[name] = DataNode(T::class, block) -} - -public inline fun DataTreeBuilder.node(name: String, noinline block: DataTreeBuilder.() -> Unit) { - this[name.toName()] = DataNode(T::class, block) -} - -/** - * Generate a mutable builder from this node. Node content is not changed - */ -public fun DataNode.builder(): DataTreeBuilder = DataTreeBuilder(type).apply { - dataSequence().forEach { (name, data) -> this[name] = data } -} - public fun DataNode.filter(predicate: (Name, Data) -> Boolean): DataNode = DataNode.invoke(type) { dataSequence().forEach { (name, data) -> if (predicate(name, data)) { @@ -293,4 +135,8 @@ public fun DataNode.filter(predicate: (Name, Data) -> Boolean): } } -public fun DataNode.first(): Data? = dataSequence().first().second \ No newline at end of file +public fun DataNode.first(): Data? = dataSequence().firstOrNull()?.second + + +public operator fun DataNode.iterator(): Iterator>> = itemSequence().iterator() + diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataTreeBuilder.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataTreeBuilder.kt new file mode 100644 index 00000000..238e862b --- /dev/null +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataTreeBuilder.kt @@ -0,0 +1,164 @@ +package hep.dataforge.data + +import hep.dataforge.meta.* +import hep.dataforge.names.* +import kotlin.reflect.KClass + +public class DataTree internal constructor( + override val type: KClass, + override val items: Map>, + override val meta: Meta +) : DataNode + +private sealed class DataTreeBuilderItem { + class Node(val tree: DataTreeBuilder) : DataTreeBuilderItem() + class Leaf(val value: Data) : DataTreeBuilderItem() +} + +/** + * A builder for a DataTree. + */ +@DFBuilder +public class DataTreeBuilder(public val type: KClass) { + private val map = HashMap>() + + private var meta = MetaBuilder() + + public operator fun set(token: NameToken, node: DataTreeBuilder) { + if (map.containsKey(token)) error("Tree entry with name $token is not empty") + map[token] = DataTreeBuilderItem.Node(node) + } + + public operator fun set(token: NameToken, data: Data) { + if (map.containsKey(token)) error("Tree entry with name $token is not empty") + map[token] = DataTreeBuilderItem.Leaf(data) + } + + private fun buildNode(token: NameToken): DataTreeBuilder { + return if (!map.containsKey(token)) { + DataTreeBuilder(type).also { map[token] = DataTreeBuilderItem.Node(it) } + } else { + (map[token] as? DataTreeBuilderItem.Node ?: error("The node with name $token is occupied by leaf")).tree + } + } + + private fun buildNode(name: Name): DataTreeBuilder { + return when (name.length) { + 0 -> this + 1 -> buildNode(name.firstOrNull()!!) + else -> buildNode(name.firstOrNull()!!).buildNode(name.cutFirst()) + } + } + + public operator fun set(name: Name, data: Data) { + when (name.length) { + 0 -> error("Can't add data with empty name") + 1 -> set(name.firstOrNull()!!, data) + 2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = data + } + } + + public operator fun set(name: Name, node: DataTreeBuilder) { + when (name.length) { + 0 -> error("Can't add data with empty name") + 1 -> set(name.firstOrNull()!!, node) + 2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = node + } + } + + public operator fun set(name: Name, node: DataNode): Unit = set(name, node.builder()) + + public operator fun set(name: Name, item: DataItem): Unit = when (item) { + is DataItem.Node -> set(name, item.node.builder()) + is DataItem.Leaf -> set(name, item.data) + } + + /** + * Append data to node + */ + public infix fun String.put(data: Data): Unit = set(toName(), data) + + /** + * Append node + */ + public infix fun String.put(node: DataNode): Unit = set(toName(), node) + + public infix fun String.put(item: DataItem): Unit = set(toName(), item) + + /** + * Build and append node + */ + public infix fun String.put(block: DataTreeBuilder.() -> Unit): Unit = set(toName(), DataTreeBuilder(type).apply(block)) + + + /** + * Update data with given node data and meta with node meta. + */ + public fun update(node: DataNode) { + node.dataSequence().forEach { + //TODO check if the place is occupied + this[it.first] = it.second + } + meta.update(node.meta) + } + + public fun meta(block: MetaBuilder.() -> Unit): MetaBuilder = meta.apply(block) + + public fun meta(meta: Meta) { + this.meta = meta.builder() + } + + public fun build(): DataTree { + val resMap = map.mapValues { (_, value) -> + when (value) { + is DataTreeBuilderItem.Leaf -> DataItem.Leaf(value.value) + is DataTreeBuilderItem.Node -> DataItem.Node(value.tree.build()) + } + } + return DataTree(type, resMap, meta.seal()) + } +} + + +public fun DataTreeBuilder.datum(name: Name, data: Data) { + this[name] = data +} + +public fun DataTreeBuilder.datum(name: String, data: Data) { + this[name.toName()] = data +} + +public fun DataTreeBuilder.static(name: Name, data: T, meta: Meta = Meta.EMPTY) { + this[name] = Data.static(data, meta) +} + +public fun DataTreeBuilder.static(name: Name, data: T, block: MetaBuilder.() -> Unit = {}) { + this[name] = Data.static(data, Meta(block)) +} + +public fun DataTreeBuilder.static(name: String, data: T, block: MetaBuilder.() -> Unit = {}) { + this[name.toName()] = Data.static(data, Meta(block)) +} + +public fun DataTreeBuilder.node(name: Name, node: DataNode) { + this[name] = node +} + +public fun DataTreeBuilder.node(name: String, node: DataNode) { + this[name.toName()] = node +} + +public inline fun DataTreeBuilder.node(name: Name, noinline block: DataTreeBuilder.() -> Unit) { + this[name] = DataNode(T::class, block) +} + +public inline fun DataTreeBuilder.node(name: String, noinline block: DataTreeBuilder.() -> Unit) { + this[name.toName()] = DataNode(T::class, block) +} + +/** + * Generate a mutable builder from this node. Node content is not changed + */ +public fun DataNode.builder(): DataTreeBuilder = DataTreeBuilder(type).apply { + dataSequence().forEach { (name, data) -> this[name] = data } +} diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Goal.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Goal.kt index e5050d22..00555a57 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Goal.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/Goal.kt @@ -5,8 +5,12 @@ import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +/** + * Lazy computation result with its dependencies to allowing to stat computing dependencies ahead of time + */ public interface Goal { public val dependencies: Collection> + /** * Returns current running coroutine if the goal is started */ @@ -16,7 +20,7 @@ public interface Goal { * Get ongoing computation or start a new one. * Does not guarantee thread safety. In case of multi-thread access, could create orphan computations. */ - public fun CoroutineScope.startAsync(): Deferred + public fun startAsync(coroutineScope: CoroutineScope): Deferred /** * Reset the computation @@ -26,7 +30,7 @@ public interface Goal { public companion object } -public suspend fun Goal.await(): T = coroutineScope { startAsync().await() } +public suspend fun Goal.await(): T = coroutineScope { startAsync(this).await() } public val Goal<*>.isComplete: Boolean get() = result?.isCompleted ?: false @@ -34,17 +38,17 @@ public open class StaticGoal(public val value: T) : Goal { override val dependencies: Collection> get() = emptyList() override val result: Deferred = CompletableDeferred(value) - override fun CoroutineScope.startAsync(): Deferred = result + override fun startAsync(coroutineScope: CoroutineScope): Deferred = result override fun reset() { //doNothing } } -public open class DynamicGoal( +public open class ComputationGoal( private val coroutineContext: CoroutineContext = EmptyCoroutineContext, override val dependencies: Collection> = emptyList(), - public val block: suspend CoroutineScope.() -> T + public val block: suspend CoroutineScope.() -> T, ) : Goal { final override var result: Deferred? = null @@ -55,19 +59,20 @@ public open class DynamicGoal( * Does not guarantee thread safety. In case of multi-thread access, could create orphan computations. */ @DFExperimental - override fun CoroutineScope.startAsync(): Deferred { - val startedDependencies = this@DynamicGoal.dependencies.map { goal -> - goal.run { startAsync() } + override fun startAsync(coroutineScope: CoroutineScope): Deferred { + val startedDependencies = this.dependencies.map { goal -> + goal.run { startAsync(coroutineScope) } } - return result - ?: async(this@DynamicGoal.coroutineContext + CoroutineMonitor() + Dependencies(startedDependencies)) { - startedDependencies.forEach { deferred -> - deferred.invokeOnCompletion { error -> - if (error != null) cancel(CancellationException("Dependency $deferred failed with error: ${error.message}")) - } + return result ?: coroutineScope.async( + this.coroutineContext + CoroutineMonitor() + Dependencies(startedDependencies) + ) { + startedDependencies.forEach { deferred -> + deferred.invokeOnCompletion { error -> + if (error != null) this.cancel(CancellationException("Dependency $deferred failed with error: ${error.message}")) } - block() - }.also { result = it } + } + block() + }.also { result = it } } /** @@ -84,8 +89,8 @@ public open class DynamicGoal( */ public fun Goal.map( coroutineContext: CoroutineContext = EmptyCoroutineContext, - block: suspend CoroutineScope.(T) -> R -): Goal = DynamicGoal(coroutineContext, listOf(this)) { + block: suspend CoroutineScope.(T) -> R, +): Goal = ComputationGoal(coroutineContext, listOf(this)) { block(await()) } @@ -94,8 +99,8 @@ public fun Goal.map( */ public fun Collection>.reduce( coroutineContext: CoroutineContext = EmptyCoroutineContext, - block: suspend CoroutineScope.(Collection) -> R -): Goal = DynamicGoal(coroutineContext, this) { + block: suspend CoroutineScope.(Collection) -> R, +): Goal = ComputationGoal(coroutineContext, this) { block(map { run { it.await() } }) } @@ -107,8 +112,8 @@ public fun Collection>.reduce( */ public fun Map>.reduce( coroutineContext: CoroutineContext = EmptyCoroutineContext, - block: suspend CoroutineScope.(Map) -> R -): Goal = DynamicGoal(coroutineContext, this.values) { + block: suspend CoroutineScope.(Map) -> R, +): Goal = ComputationGoal(coroutineContext, this.values) { block(mapValues { it.value.await() }) } diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt index e5504530..c1ba2074 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt @@ -30,46 +30,41 @@ public class MapActionBuilder(public var name: Name, public var meta: Meta public class MapAction( - public val inputType: KClass, public val outputType: KClass, private val block: MapActionBuilder.() -> Unit ) : Action { - override fun invoke(node: DataNode, meta: Meta): DataNode { - node.ensureType(inputType) + override fun invoke(node: DataNode, meta: Meta): DataNode = DataNode(outputType) { + node.dataSequence().forEach { (name, data) -> + /* + * Creating a new environment for action using **old** name, old meta and task meta + */ + val env = ActionEnv(name, data.meta, meta) - return DataNode.invoke(outputType) { - node.dataSequence().forEach { (name, data) -> - /* - * Creating a new environment for action using **old** name, old meta and task meta - */ - val env = ActionEnv(name, data.meta, meta) + //applying transformation from builder + val builder = MapActionBuilder( + name, + data.meta.builder(), // using data meta + meta + ).apply(block) - //applying transformation from builder - val builder = MapActionBuilder( - name, - data.meta.builder(), // using data meta - meta - ).apply(block) + //getting new name + val newName = builder.name - //getting new name - val newName = builder.name + //getting new meta + val newMeta = builder.meta.seal() - //getting new meta - val newMeta = builder.meta.seal() - - val newData = data.map(outputType, meta = newMeta) { builder.result(env, it) } - //setting the data node - this[newName] = newData - } + val newData = data.map(outputType, meta = newMeta) { builder.result(env, it) } + //setting the data node + this[newName] = newData } } } -public inline fun DataNode.map( +public inline fun DataNode.map( meta: Meta, noinline action: MapActionBuilder.() -> Unit -): DataNode = MapAction(T::class, R::class, action).invoke(this, meta) +): DataNode = MapAction(R::class, action).invoke(this, meta) diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt index a0227af9..d9d9dec2 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt @@ -72,35 +72,31 @@ public class ReduceGroupBuilder(public val actionMeta: Meta) { * The same rules as for KPipe */ public class ReduceAction( - public val inputType: KClass, public val outputType: KClass, private val action: ReduceGroupBuilder.() -> Unit ) : Action { - override fun invoke(node: DataNode, meta: Meta): DataNode { - node.ensureType(inputType) - return DataNode.invoke(outputType) { - ReduceGroupBuilder(meta).apply(action).buildGroups(node).forEach { group -> + override fun invoke(node: DataNode, meta: Meta): DataNode = DataNode(outputType) { + ReduceGroupBuilder(meta).apply(action).buildGroups(node).forEach { group -> - //val laminate = Laminate(group.meta, meta) + //val laminate = Laminate(group.meta, meta) - val dataMap = group.node.dataSequence().associate { it } + val dataMap = group.node.dataSequence().associate { it } - val groupName: String = group.name + val groupName: String = group.name - val groupMeta = group.meta + val groupMeta = group.meta - val env = ActionEnv(groupName.toName(), groupMeta, meta) + val env = ActionEnv(groupName.toName(), groupMeta, meta) - val res: DynamicData = dataMap.reduce( - outputType, - meta = groupMeta - ) { group.result.invoke(env, it) } - - set(env.name, res) - } + val res: ComputationData = dataMap.reduce( + outputType, + meta = groupMeta + ) { group.result.invoke(env, it) } + set(env.name, res) } + } } diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt index 731a9403..70fbec96 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt @@ -33,31 +33,26 @@ public class SplitBuilder(public val name: Name, public val me } public class SplitAction( - public val inputType: KClass, public val outputType: KClass, private val action: SplitBuilder.() -> Unit ) : Action { - override fun invoke(node: DataNode, meta: Meta): DataNode { - node.ensureType(inputType) + override fun invoke(node: DataNode, meta: Meta): DataNode = DataNode(outputType) { + node.dataSequence().forEach { (name, data) -> - return DataNode.invoke(outputType) { - node.dataSequence().forEach { (name, data) -> + val laminate = Laminate(data.meta, meta) - val laminate = Laminate(data.meta, meta) - - val split = SplitBuilder(name, data.meta).apply(action) + val split = SplitBuilder(name, data.meta).apply(action) - // apply individual fragment rules to result - split.fragments.forEach { (fragmentName, rule) -> - val env = FragmentRule(fragmentName, laminate.builder()) + // apply individual fragment rules to result + split.fragments.forEach { (fragmentName, rule) -> + val env = FragmentRule(fragmentName, laminate.builder()) - rule(env) + rule(env) - val res = data.map(outputType, meta = env.meta) { env.result(it) } - set(env.name, res) - } + val res = data.map(outputType, meta = env.meta) { env.result(it) } + set(env.name, res) } } } diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/dataCast.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/dataCast.kt deleted file mode 100644 index 26563bc8..00000000 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/dataCast.kt +++ /dev/null @@ -1,73 +0,0 @@ -package hep.dataforge.data - -import hep.dataforge.meta.Meta -import hep.dataforge.names.NameToken -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlin.reflect.KClass - -public fun Data.upcast(type: KClass): Data { - return object : Data by this { - override val type: KClass = type - } -} - -/** - * Safe upcast a [Data] to a supertype - */ -public inline fun Data.upcast(): Data = upcast(R::class) - -/** - * Check if node could be safely cast to given class - */ -internal expect fun DataNode<*>.canCast(type: KClass): Boolean - -/** - * Check if data could be safely cast to given class - */ -internal expect fun Data<*>.canCast(type: KClass): Boolean - -public fun DataItem<*>.canCast(type: KClass): Boolean = when (this) { - is DataItem.Node -> node.canCast(type) - is DataItem.Leaf -> data.canCast(type) -} - -/** - * Unsafe cast of data node - */ -@Suppress("UNCHECKED_CAST") -public fun Data<*>.cast(type: KClass): Data { - return object : Data { - override val meta: Meta get() = this@cast.meta - override val dependencies: Collection> get() = this@cast.dependencies - override val result: Deferred? get() = this@cast.result as Deferred - override fun CoroutineScope.startAsync(): Deferred = this@cast.run { startAsync() as Deferred } - override fun reset() = this@cast.reset() - override val type: KClass = type - } -} - -public inline fun Data<*>.cast(): Data = cast(R::class) - -@Suppress("UNCHECKED_CAST") -public fun DataNode<*>.cast(type: KClass): DataNode { - return object : DataNode { - override val meta: Meta get() = this@cast.meta - override val type: KClass = type - override val items: Map> get() = this@cast.items as Map> - } -} - -public inline fun DataNode<*>.cast(): DataNode = cast(R::class) - -/** - * Check that node is compatible with given type meaning that each element could be cast to the type - */ -public fun DataNode<*>.ensureType(type: KClass) { - if (!canCast(type)) { - error("$type expected, but $type received") - } -} - - -//expect fun DataNode.cast(type: KClass): DataNode \ No newline at end of file diff --git a/dataforge-data/src/jsMain/kotlin/hep/dataforge/data/dataJS.kt b/dataforge-data/src/jsMain/kotlin/hep/dataforge/data/dataJS.kt deleted file mode 100644 index 0257b85a..00000000 --- a/dataforge-data/src/jsMain/kotlin/hep/dataforge/data/dataJS.kt +++ /dev/null @@ -1,14 +0,0 @@ -package hep.dataforge.data - -import kotlin.reflect.KClass - -/** - * Check that node is compatible with given type meaning that each element could be cast to the type - */ -internal actual fun DataNode<*>.canCast(type: KClass): Boolean { - return this.type == type -} - -internal actual fun Data<*>.canCast(type: KClass): Boolean { - return this.type == type -} diff --git a/dataforge-data/src/jvmMain/kotlin/hep/dataforge/data/dataJVM.kt b/dataforge-data/src/jvmMain/kotlin/hep/dataforge/data/dataJVM.kt index 6f758dae..877b6dbc 100644 --- a/dataforge-data/src/jvmMain/kotlin/hep/dataforge/data/dataJVM.kt +++ b/dataforge-data/src/jvmMain/kotlin/hep/dataforge/data/dataJVM.kt @@ -1,5 +1,9 @@ package hep.dataforge.data +import hep.dataforge.meta.Meta +import hep.dataforge.names.NameToken +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred import kotlinx.coroutines.runBlocking import kotlin.reflect.KClass import kotlin.reflect.full.isSubclassOf @@ -12,12 +16,72 @@ public fun Data.get(): T = runBlocking { await() } /** * Check that node is compatible with given type meaning that each element could be cast to the type */ -internal actual fun DataNode<*>.canCast(type: KClass): Boolean = +internal fun DataNode<*>.canCast(type: KClass): Boolean = type.isSubclassOf(this.type) - -internal actual fun Data<*>.canCast(type: KClass): Boolean = +/** + * Check if data could be safely cast to given class + */ +internal fun Data<*>.canCast(type: KClass): Boolean = this.type.isSubclassOf(type) + +public fun Data.upcast(type: KClass): Data { + return object : Data by this { + override val type: KClass = type + } +} + +/** + * Safe upcast a [Data] to a supertype + */ +public inline fun Data.upcast(): Data = upcast(R::class) + +public fun DataItem<*>.canCast(type: KClass): Boolean = when (this) { + is DataItem.Node -> node.canCast(type) + is DataItem.Leaf -> data.canCast(type) +} + +/** + * Unsafe cast of data node + */ +@Suppress("UNCHECKED_CAST") +public fun Data<*>.cast(type: KClass): Data { + if(!canCast(type)) error("Can't cast ${this.type} to $type") + return object : Data { + override val meta: Meta get() = this@cast.meta + override val dependencies: Collection> get() = this@cast.dependencies + override val result: Deferred? get() = this@cast.result as Deferred? + override fun startAsync(coroutineScope: CoroutineScope): Deferred = this@cast.run { + startAsync(coroutineScope) as Deferred + } + + override fun reset() = this@cast.reset() + override val type: KClass = type + } +} + +public inline fun Data<*>.cast(): Data = cast(R::class) + +@Suppress("UNCHECKED_CAST") +public fun DataNode<*>.cast(type: KClass): DataNode { + return object : DataNode { + override val meta: Meta get() = this@cast.meta + override val type: KClass = type + override val items: Map> get() = this@cast.items as Map> + } +} + +public inline fun DataNode<*>.cast(): DataNode = cast(R::class) + +/** + * Check that node is compatible with given type meaning that each element could be cast to the type + */ +public fun DataNode<*>.ensureType(type: KClass) { + if (!canCast(type)) { + error("$type expected, but $type received") + } +} + /** * Cast the node to given type if the cast is possible or return null */ diff --git a/dataforge-data/src/nativeMain/kotlin/hep/dataforge/data/dataNative.kt b/dataforge-data/src/nativeMain/kotlin/hep/dataforge/data/dataNative.kt deleted file mode 100644 index fe770f88..00000000 --- a/dataforge-data/src/nativeMain/kotlin/hep/dataforge/data/dataNative.kt +++ /dev/null @@ -1,14 +0,0 @@ -package hep.dataforge.data - -import kotlin.reflect.KClass - -/** - * Check that node is compatible with given type meaning that each element could be cast to the type - */ -internal actual fun DataNode<*>.canCast(type: KClass): Boolean { - return this.type == type -} - -internal actual fun Data<*>.canCast(type: KClass): Boolean { - return this.type == type -} \ No newline at end of file diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/EnvelopeFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/EnvelopeFormat.kt index b02052c1..06cc9374 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/EnvelopeFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/EnvelopeFormat.kt @@ -5,7 +5,7 @@ import hep.dataforge.io.EnvelopeFormatFactory.Companion.ENVELOPE_FORMAT_TYPE import hep.dataforge.meta.Meta import hep.dataforge.names.Name import hep.dataforge.names.asName -import hep.dataforge.provider.Type +import hep.dataforge.type.Type import kotlinx.io.Input import kotlinx.io.Output import kotlin.reflect.KClass diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt index aac83ae6..1fd845ea 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt @@ -10,7 +10,7 @@ import hep.dataforge.meta.MetaRepr import hep.dataforge.meta.ValueItem import hep.dataforge.names.Name import hep.dataforge.names.asName -import hep.dataforge.provider.Type +import hep.dataforge.type.Type import hep.dataforge.values.Value import kotlinx.io.* import kotlinx.io.buffer.Buffer diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt index f3e26d2a..0fa51555 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt @@ -7,7 +7,7 @@ import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.plus -import hep.dataforge.provider.Type +import hep.dataforge.type.Type import kotlinx.io.ByteArrayInput import kotlinx.io.Input import kotlinx.io.Output diff --git a/dataforge-meta/api/dataforge-meta.api b/dataforge-meta/api/dataforge-meta.api index 3e85187f..113bf7e1 100644 --- a/dataforge-meta/api/dataforge-meta.api +++ b/dataforge-meta/api/dataforge-meta.api @@ -812,6 +812,10 @@ public final class hep/dataforge/names/NameTokenKt { public static final fun withIndex (Lhep/dataforge/names/NameToken;Ljava/lang/String;)Lhep/dataforge/names/NameToken; } +public abstract interface annotation class hep/dataforge/type/Type : java/lang/annotation/Annotation { + public abstract fun id ()Ljava/lang/String; +} + public final class hep/dataforge/values/DoubleArrayValue : hep/dataforge/values/Value, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { public fun ([D)V public fun equals (Ljava/lang/Object;)Z diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Type.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/type/Type.kt similarity index 90% rename from dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Type.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/type/Type.kt index e07cfd10..34c2a113 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Type.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/type/Type.kt @@ -1,4 +1,4 @@ -package hep.dataforge.provider +package hep.dataforge.type /** * A text label for internal DataForge type classification. Alternative for mime container type. diff --git a/dataforge-workspace/api/dataforge-workspace.api b/dataforge-workspace/api/dataforge-workspace.api index c599d391..d510660b 100644 --- a/dataforge-workspace/api/dataforge-workspace.api +++ b/dataforge-workspace/api/dataforge-workspace.api @@ -210,8 +210,6 @@ public abstract interface class hep/dataforge/workspace/Workspace : hep/dataforg public final class hep/dataforge/workspace/Workspace$Companion { public static final field TYPE Ljava/lang/String; - public final fun invoke (Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/workspace/SimpleWorkspace; - public static synthetic fun invoke$default (Lhep/dataforge/workspace/Workspace$Companion;Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/workspace/SimpleWorkspace; } public final class hep/dataforge/workspace/Workspace$DefaultImpls { @@ -235,6 +233,8 @@ public abstract interface class hep/dataforge/workspace/WorkspaceBuilder { } public final class hep/dataforge/workspace/WorkspaceBuilderKt { + public static final fun Workspace (Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/workspace/Workspace; + public static synthetic fun Workspace$default (Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/workspace/Workspace; public static final fun context (Lhep/dataforge/workspace/WorkspaceBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public static synthetic fun context$default (Lhep/dataforge/workspace/WorkspaceBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public static final fun rawData (Lhep/dataforge/workspace/WorkspaceBuilder;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/data/DataNode; diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt index 6792adfa..9534c7ec 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt @@ -4,7 +4,7 @@ import hep.dataforge.context.Named import hep.dataforge.data.DataNode import hep.dataforge.meta.Meta import hep.dataforge.meta.descriptors.Described -import hep.dataforge.provider.Type +import hep.dataforge.type.Type import hep.dataforge.workspace.Task.Companion.TYPE import kotlin.reflect.KClass diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt index b9aaad18..589dce0a 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt @@ -1,8 +1,6 @@ package hep.dataforge.workspace -import hep.dataforge.context.Context import hep.dataforge.context.ContextAware -import hep.dataforge.context.Global import hep.dataforge.data.Data import hep.dataforge.data.DataNode import hep.dataforge.data.dataSequence @@ -11,7 +9,7 @@ import hep.dataforge.meta.MetaBuilder import hep.dataforge.names.Name import hep.dataforge.names.toName import hep.dataforge.provider.Provider -import hep.dataforge.provider.Type +import hep.dataforge.type.Type @Type(Workspace.TYPE) @@ -52,11 +50,6 @@ public interface Workspace : ContextAware, Provider { public companion object { public const val TYPE: String = "workspace" - public operator fun invoke( - parent: Context = Global, - block: SimpleWorkspaceBuilder.() -> Unit, - ): SimpleWorkspace = - SimpleWorkspaceBuilder(parent).apply(block).build() } } diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt b/dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt similarity index 81% rename from dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt rename to dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt index f25faa97..3117473f 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt +++ b/dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt @@ -11,7 +11,6 @@ import hep.dataforge.meta.string import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.names.toName -import kotlin.jvm.JvmName import kotlin.reflect.KClass @DFBuilder @@ -28,7 +27,7 @@ public class TaskBuilder(public val name: Name, public val type: KClass private inner class DataTransformation( val from: String = "", val to: String = "", - val transform: (Context, TaskModel, DataNode) -> DataNode + val transform: (Context, TaskModel, DataNode) -> DataNode, ) { operator fun invoke(workspace: Workspace, model: TaskModel, node: DataNode): DataNode? { val localData = if (from.isEmpty()) { @@ -55,7 +54,7 @@ public class TaskBuilder(public val name: Name, public val type: KClass public fun transform( from: String = "", to: String = "", - block: TaskEnv.(DataNode<*>) -> DataNode + block: TaskEnv.(DataNode<*>) -> DataNode, ) { dataTransforms += DataTransformation(from, to) { context, model, data -> val env = TaskEnv(Name.EMPTY, model.meta, context, data) @@ -67,7 +66,7 @@ public class TaskBuilder(public val name: Name, public val type: KClass inputType: KClass, from: String = "", to: String = "", - block: TaskEnv.(DataNode) -> DataNode + block: TaskEnv.(DataNode) -> DataNode, ) { dataTransforms += DataTransformation(from, to) { context, model, data -> data.ensureType(inputType) @@ -79,7 +78,7 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun transform( from: String = "", to: String = "", - noinline block: TaskEnv.(DataNode) -> DataNode + noinline block: TaskEnv.(DataNode) -> DataNode, ) { transform(T::class, from, to, block) } @@ -90,14 +89,19 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun action( from: String = "", to: String = "", - crossinline block: TaskEnv.() -> Action + crossinline block: TaskEnv.() -> Action, ) { transform(from, to) { data: DataNode -> block().invoke(data, meta) } } - public class TaskEnv(public val name: Name, public val meta: Meta, public val context: Context, public val data: DataNode) { + public class TaskEnv( + public val name: Name, + public val meta: Meta, + public val context: Context, + public val data: DataNode, + ) { public operator fun DirectTaskDependency.invoke(): DataNode = if (placement.isEmpty()) { data.cast(task.type) } else { @@ -112,14 +116,11 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun mapAction( from: String = "", to: String = "", - crossinline block: MapActionBuilder.(TaskEnv) -> Unit + crossinline block: MapActionBuilder.(TaskEnv) -> Unit, ) { action(from, to) { val env = this - MapAction( - inputType = T::class, - outputType = type - ) { + MapAction(type) { block(env) } } @@ -131,13 +132,10 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun map( from: String = "", to: String = "", - crossinline block: suspend TaskEnv.(T) -> R + crossinline block: suspend TaskEnv.(T) -> R, ) { action(from, to) { - MapAction( - inputType = T::class, - outputType = type - ) { + MapAction(type) { //TODO automatically append task meta result = { data -> block(data) @@ -152,14 +150,11 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun reduceByGroup( from: String = "", to: String = "", - crossinline block: ReduceGroupBuilder.(TaskEnv) -> Unit //TODO needs KEEP-176 + crossinline block: ReduceGroupBuilder.(TaskEnv) -> Unit, //TODO needs KEEP-176 ) { action(from, to) { val env = this - ReduceAction( - inputType = T::class, - outputType = type - ) { block(env) } + ReduceAction(type) { block(env) } } } @@ -169,20 +164,16 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun reduce( from: String = "", to: String = "", - crossinline block: suspend TaskEnv.(Map) -> R + crossinline block: suspend TaskEnv.(Map) -> R, ) { action(from, to) { - ReduceAction( - inputType = T::class, - outputType = type, - action = { - result( - actionMeta[TaskModel.MODEL_TARGET_KEY]?.string ?: "@anonymous" - ) { data -> - block(data) - } + ReduceAction(type) { + result( + actionMeta[TaskModel.MODEL_TARGET_KEY]?.string ?: "@anonymous" + ) { data -> + block(data) } - ) + } } } @@ -192,14 +183,11 @@ public class TaskBuilder(public val name: Name, public val type: KClass public inline fun split( from: String = "", to: String = "", - crossinline block: SplitBuilder.(TaskEnv) -> Unit //TODO needs KEEP-176 + crossinline block: SplitBuilder.(TaskEnv) -> Unit, //TODO needs KEEP-176 ) { action(from, to) { val env = this - SplitAction( - inputType = T::class, - outputType = type - ) { block(env) } + SplitAction(type) { block(this, env) } } } diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt b/dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt similarity index 93% rename from dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt rename to dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt index b7f74079..1b2b0cdb 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt +++ b/dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/WorkspaceBuilder.kt @@ -2,13 +2,13 @@ package hep.dataforge.workspace import hep.dataforge.context.Context import hep.dataforge.context.ContextBuilder +import hep.dataforge.context.Global import hep.dataforge.data.DataNode import hep.dataforge.data.DataTreeBuilder import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.isEmpty import hep.dataforge.names.toName -import kotlin.jvm.JvmName import kotlin.reflect.KClass @DFBuilder @@ -95,4 +95,9 @@ public class SimpleWorkspaceBuilder(override val parentContext: Context) : Works override fun build(): SimpleWorkspace { return SimpleWorkspace(context, data.build(), targets, tasks) } -} \ No newline at end of file +} + +public fun Workspace( + parent: Context = Global, + block: SimpleWorkspaceBuilder.() -> Unit, +): Workspace = SimpleWorkspaceBuilder(parent).apply(block).build() \ No newline at end of file diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/WorkspacePlugin.kt b/dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/WorkspacePlugin.kt similarity index 100% rename from dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/WorkspacePlugin.kt rename to dataforge-workspace/src/jvmMain/kotlin/hep/dataforge/workspace/WorkspacePlugin.kt