diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/AbstractPlugin.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/AbstractPlugin.kt index 4c1e86d1..9a091ad1 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/AbstractPlugin.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/AbstractPlugin.kt @@ -20,5 +20,5 @@ abstract class AbstractPlugin(override val meta: Meta = EmptyMeta) : Plugin { override fun provideTop(target: String, name: Name): Any? = null - override fun listTop(target: String): Sequence = emptySequence() + override fun listNames(target: String): Sequence = emptySequence() } \ No newline at end of file diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt index bf5c8924..cf6bb662 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -2,9 +2,10 @@ package hep.dataforge.context import hep.dataforge.meta.* import hep.dataforge.names.Name +import hep.dataforge.names.appendLeft import hep.dataforge.names.toName import hep.dataforge.provider.Provider -import hep.dataforge.provider.provideAll +import hep.dataforge.provider.top import hep.dataforge.values.Value import kotlinx.coroutines.CoroutineScope import mu.KLogger @@ -66,7 +67,7 @@ open class Context(final override val name: String, val parent: Context? = Globa } } - override fun listTop(target: String): Sequence { + override fun listNames(target: String): Sequence { return when (target) { Plugin.PLUGIN_TARGET -> plugins.asSequence().map { it.name.toName() } Value.TYPE -> properties.values().map { it.first } @@ -118,12 +119,13 @@ open class Context(final override val name: String, val parent: Context? = Globa /** * A sequences of all objects provided by plugins with given target and type */ -fun Context.members(target: String): Sequence = - plugins.asSequence().flatMap { it.provideAll(target) } +fun Context.content(target: String): Map = content(target) -@JvmName("typedMembers") -inline fun Context.members(target: String) = - members(target).filterIsInstance() +@JvmName("typedContent") +inline fun Context.content(target: String): Map = + plugins.flatMap { plugin -> + plugin.top(target).entries.map { (it.key.appendLeft(plugin.name)) to it.value } + }.associate { it } /** diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Provider.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Provider.kt index 79b94dce..657f272d 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Provider.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/provider/Provider.kt @@ -17,6 +17,7 @@ package hep.dataforge.provider import hep.dataforge.names.Name import hep.dataforge.names.toName +import kotlin.jvm.JvmName /** * A marker utility interface for providers. @@ -51,7 +52,7 @@ interface Provider { * @param target * @return */ - fun listTop(target: String): Sequence + fun listNames(target: String): Sequence } fun Provider.provide(path: Path, targetOverride: String? = null): Any? { @@ -77,15 +78,23 @@ inline fun Provider.provide(path: String): T? { return provide(Path.parse(path)) as? T } -inline fun Provider.provide(target: String, name: String): T? { - return provide(PathToken(name.toName(), target).toPath()) as? T +inline fun Provider.provide(target: String, name: Name): T? { + return provide(PathToken(name, target).toPath()) as? T } +inline fun Provider.provide(target: String, name: String): T? = + provide(target, name.toName()) + /** - * [Sequence] of all elements with given target + * A top level content with names */ -fun Provider.provideAll(target: String): Sequence { - return listTop(target).map { provideTop(target, it) ?: error("The element $it is declared but not provided") } +fun Provider.top(target: String): Map = top(target) + +@JvmName("typedTop") +inline fun Provider.top(target: String): Map { + return listNames(target).associate { + it to (provideTop(target, it) as? T ?: error("The element $it is declared but not provided")) + } } diff --git a/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt b/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt index f598d44c..bf761b8e 100644 --- a/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt +++ b/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt @@ -17,10 +17,10 @@ class ContextTest { } } - override fun listTop(target: String): Sequence { + override fun listNames(target: String): Sequence { return when (target) { "test" -> sequenceOf("a", "b", "c.d").map { it.toName() } - else -> super.listTop(target) + else -> super.listNames(target) } } } @@ -28,7 +28,7 @@ class ContextTest { @Test fun testPluginManager() { Global.plugins.load(DummyPlugin()) - val members = Global.members("test") + val members = Global.content("test") assertEquals(3, members.count()) members.forEach { println(it) diff --git a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/Types.kt b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/Types.kt index 15cfe2d1..d6ed723d 100644 --- a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/Types.kt +++ b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/provider/Types.kt @@ -1,11 +1,14 @@ package hep.dataforge.provider import hep.dataforge.context.Context -import hep.dataforge.context.members +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()?.id ?: cl.simpleName ?: "" @@ -24,13 +27,20 @@ inline fun Provider.provideByType(name: String): T? { return provide(target, name) } -inline fun Provider.provideAllByType(): Sequence { +inline fun Provider.provideByType(name: Name): T? { val target = Types[T::class] - return provideAll(target).filterIsInstance() + return provide(target, name) +} + +inline fun Provider.top(): Map { + val target = Types[T::class] + return listNames(target).associate { name -> + name to (provideByType(name) ?: error("The element $name is declared but not provided")) + } } /** * A sequences of all objects provided by plugins with given target and type */ -inline fun Context.members(): Sequence = members(Types[T::class]) +inline fun Context.content(): Map = content(Types[T::class]) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt index 9179f16e..d8513e9c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt @@ -102,6 +102,8 @@ operator fun Name.plus(other: Name): Name = Name(this.tokens + other.tokens) operator fun Name.plus(other: String): Name = this + other.toName() +fun Name.appendLeft(other: String): Name = NameToken(other) + this + fun NameToken.asName() = Name(listOf(this)) val EmptyName = Name(emptyList()) diff --git a/dataforge-output/dataforge-output-html/src/jvmMain/kotlin/hep/dataforge/output/html/HtmlOutput.kt b/dataforge-output/dataforge-output-html/src/jvmMain/kotlin/hep/dataforge/output/html/HtmlOutput.kt index fbb87196..bfbd74eb 100644 --- a/dataforge-output/dataforge-output-html/src/jvmMain/kotlin/hep/dataforge/output/html/HtmlOutput.kt +++ b/dataforge-output/dataforge-output-html/src/jvmMain/kotlin/hep/dataforge/output/html/HtmlOutput.kt @@ -4,11 +4,9 @@ import hep.dataforge.context.Context import hep.dataforge.meta.Meta import hep.dataforge.output.Output import hep.dataforge.output.TextRenderer -import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE import hep.dataforge.output.html.HtmlBuilder.Companion.HTML_CONVERTER_TYPE import hep.dataforge.provider.Type -import hep.dataforge.provider.provideAll -import hep.dataforge.provider.provideAllByType +import hep.dataforge.provider.top import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.html.TagConsumer @@ -29,7 +27,7 @@ class HtmlOutput(override val context: Context, private val consumer: T } else { val value = cache[obj::class] if (value == null) { - val answer = context.provideAllByType>() + val answer = context.top>().values .filter { it.type.isInstance(obj) }.firstOrNull() if (answer != null) { cache[obj::class] = answer diff --git a/dataforge-output/src/commonMain/kotlin/hep/dataforge/output/TextOutput.kt b/dataforge-output/src/commonMain/kotlin/hep/dataforge/output/TextOutput.kt index 673e8e07..91aa5024 100644 --- a/dataforge-output/src/commonMain/kotlin/hep/dataforge/output/TextOutput.kt +++ b/dataforge-output/src/commonMain/kotlin/hep/dataforge/output/TextOutput.kt @@ -1,10 +1,10 @@ package hep.dataforge.output import hep.dataforge.context.Context -import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE import hep.dataforge.meta.Meta +import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE import hep.dataforge.provider.Type -import hep.dataforge.provider.provideAll +import hep.dataforge.provider.top import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlin.reflect.KClass @@ -21,8 +21,8 @@ class TextOutput(override val context: Context, private val output: kotlinx.io.c } else { val value = cache[obj::class] if (value == null) { - val answer = context.provideAll(TEXT_RENDERER_TYPE).filterIsInstance() - .filter { it.type.isInstance(obj) }.firstOrNull() + val answer = + context.top(TEXT_RENDERER_TYPE).values.firstOrNull { it.type.isInstance(obj) } if (answer != null) { cache[obj::class] = answer answer diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Dependency.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Dependency.kt index 1aa4bbb1..24c012ea 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Dependency.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Dependency.kt @@ -8,6 +8,7 @@ import hep.dataforge.meta.MetaRepr import hep.dataforge.meta.buildMeta import hep.dataforge.names.EmptyName import hep.dataforge.names.Name +import hep.dataforge.names.get import hep.dataforge.names.isEmpty /** @@ -49,7 +50,7 @@ class AllDataDependency(val placement: Name = EmptyName) : Dependency() { class TaskModelDependency(val name: String, val meta: Meta, val placement: Name = EmptyName) : Dependency() { override fun apply(workspace: Workspace): DataNode { - val task = workspace.tasks[name] ?: error("Task with name ${name} is not found in the workspace") + val task = workspace.tasks[name] ?: error("Task with name $name is not found in the workspace") if (task.isTerminal) TODO("Support terminal task") val result = workspace.run(task, meta) return if (placement.isEmpty()) { diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/SimpleWorkspace.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/SimpleWorkspace.kt index 16ab8f6f..c7a54f3d 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/SimpleWorkspace.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/SimpleWorkspace.kt @@ -2,9 +2,11 @@ package hep.dataforge.workspace import hep.dataforge.context.Context import hep.dataforge.context.Global -import hep.dataforge.context.members import hep.dataforge.data.DataNode import hep.dataforge.meta.Meta +import hep.dataforge.names.Name +import hep.dataforge.names.toName +import hep.dataforge.provider.top /** @@ -16,8 +18,8 @@ class SimpleWorkspace( override val targets: Map, tasks: Collection> ) : Workspace { - override val tasks: Map> by lazy { - (context.members>(Task.TYPE) + tasks).associate { it.name to it } + override val tasks: Map> by lazy { + context.top>(Task.TYPE) + tasks.associate { it.name.toName() to it } } companion object { 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 89af04a2..1945c74e 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt @@ -27,22 +27,22 @@ interface Workspace : ContextAware, Provider { /** * All tasks associated with the workspace */ - val tasks: Map> + val tasks: Map> override fun provideTop(target: String, name: Name): Any? { return when (target) { "target", Meta.TYPE -> targets[name.toString()] - Task.TYPE -> tasks[name.toString()] + Task.TYPE -> tasks[name] Data.TYPE -> data[name] DataNode.TYPE -> data.getNode(name) else -> null } } - override fun listTop(target: String): Sequence { + override fun listNames(target: String): Sequence { return when (target) { "target", Meta.TYPE -> targets.keys.asSequence().map { it.toName() } - Task.TYPE -> tasks.keys.asSequence().map { it.toName() } + Task.TYPE -> tasks.keys.asSequence().map { it } Data.TYPE -> data.data().map { it.first } DataNode.TYPE -> data.nodes().map { it.first } else -> emptySequence() @@ -85,10 +85,10 @@ fun Workspace.run(task: Task<*>, target: String): DataNode { fun Workspace.run(task: String, target: String) = - tasks[task]?.let { run(it, target) } ?: error("Task with name $task not found") + tasks[task.toName()]?.let { run(it, target) } ?: error("Task with name $task not found") fun Workspace.run(task: String, meta: Meta) = - tasks[task]?.let { run(it, meta) } ?: error("Task with name $task not found") + tasks[task.toName()]?.let { run(it, meta) } ?: error("Task with name $task not found") fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}) = run(task, buildMeta(block))