Providers provide map instead of sequence on provideAll (replaced by top).

Context task loading ambiguity solved by prepending plugin name.
This commit is contained in:
Alexander Nozik 2019-05-08 22:15:44 +03:00
parent f284d15ee4
commit 52fb8234fc
11 changed files with 64 additions and 40 deletions

View File

@ -20,5 +20,5 @@ abstract class AbstractPlugin(override val meta: Meta = EmptyMeta) : Plugin {
override fun provideTop(target: String, name: Name): Any? = null override fun provideTop(target: String, name: Name): Any? = null
override fun listTop(target: String): Sequence<Name> = emptySequence() override fun listNames(target: String): Sequence<Name> = emptySequence()
} }

View File

@ -2,9 +2,10 @@ package hep.dataforge.context
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.appendLeft
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.provider.Provider import hep.dataforge.provider.Provider
import hep.dataforge.provider.provideAll import hep.dataforge.provider.top
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import mu.KLogger 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<Name> { override fun listNames(target: String): Sequence<Name> {
return when (target) { return when (target) {
Plugin.PLUGIN_TARGET -> plugins.asSequence().map { it.name.toName() } Plugin.PLUGIN_TARGET -> plugins.asSequence().map { it.name.toName() }
Value.TYPE -> properties.values().map { it.first } 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 * A sequences of all objects provided by plugins with given target and type
*/ */
fun Context.members(target: String): Sequence<Any> = fun Context.content(target: String): Map<Name, Any> = content<Any>(target)
plugins.asSequence().flatMap { it.provideAll(target) }
@JvmName("typedMembers") @JvmName("typedContent")
inline fun <reified T : Any> Context.members(target: String) = inline fun <reified T : Any> Context.content(target: String): Map<Name, T> =
members(target).filterIsInstance<T>() plugins.flatMap { plugin ->
plugin.top<T>(target).entries.map { (it.key.appendLeft(plugin.name)) to it.value }
}.associate { it }
/** /**

View File

@ -17,6 +17,7 @@ package hep.dataforge.provider
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import kotlin.jvm.JvmName
/** /**
* A marker utility interface for providers. * A marker utility interface for providers.
@ -51,7 +52,7 @@ interface Provider {
* @param target * @param target
* @return * @return
*/ */
fun listTop(target: String): Sequence<Name> fun listNames(target: String): Sequence<Name>
} }
fun Provider.provide(path: Path, targetOverride: String? = null): Any? { fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
@ -77,15 +78,23 @@ inline fun <reified T : Any> Provider.provide(path: String): T? {
return provide(Path.parse(path)) as? T return provide(Path.parse(path)) as? T
} }
inline fun <reified T : Any> Provider.provide(target: String, name: String): T? { inline fun <reified T : Any> Provider.provide(target: String, name: Name): T? {
return provide(PathToken(name.toName(), target).toPath()) as? 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())
/** /**
* [Sequence] of all elements with given target * A top level content with names
*/ */
fun Provider.provideAll(target: String): Sequence<Any> { fun Provider.top(target: String): Map<Name, Any> = top<Any>(target)
return listTop(target).map { provideTop(target, it) ?: error("The element $it is declared but not provided") }
@JvmName("typedTop")
inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> {
return listNames(target).associate {
it to (provideTop(target, it) as? T ?: error("The element $it is declared but not provided"))
}
} }

View File

@ -17,10 +17,10 @@ class ContextTest {
} }
} }
override fun listTop(target: String): Sequence<Name> { override fun listNames(target: String): Sequence<Name> {
return when (target) { return when (target) {
"test" -> sequenceOf("a", "b", "c.d").map { it.toName() } "test" -> sequenceOf("a", "b", "c.d").map { it.toName() }
else -> super.listTop(target) else -> super.listNames(target)
} }
} }
} }
@ -28,7 +28,7 @@ class ContextTest {
@Test @Test
fun testPluginManager() { fun testPluginManager() {
Global.plugins.load(DummyPlugin()) Global.plugins.load(DummyPlugin())
val members = Global.members<Name>("test") val members = Global.content<Name>("test")
assertEquals(3, members.count()) assertEquals(3, members.count())
members.forEach { members.forEach {
println(it) println(it)

View File

@ -1,11 +1,14 @@
package hep.dataforge.provider package hep.dataforge.provider
import hep.dataforge.context.Context 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.KClass
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
/**
*
*/
object Types { object Types {
operator fun get(cl: KClass<*>): String { operator fun get(cl: KClass<*>): String {
return cl.findAnnotation<Type>()?.id ?: cl.simpleName ?: "" return cl.findAnnotation<Type>()?.id ?: cl.simpleName ?: ""
@ -24,13 +27,20 @@ inline fun <reified T : Any> Provider.provideByType(name: String): T? {
return provide(target, name) return provide(target, name)
} }
inline fun <reified T : Any> Provider.provideAllByType(): Sequence<T> { inline fun <reified T : Any> Provider.provideByType(name: Name): T? {
val target = Types[T::class] val target = Types[T::class]
return provideAll(target).filterIsInstance<T>() return provide(target, name)
}
inline fun <reified T : Any> Provider.top(): Map<Name, T> {
val target = Types[T::class]
return listNames(target).associate { name ->
name to (provideByType<T>(name) ?: error("The element $name is declared but not provided"))
}
} }
/** /**
* A sequences of all objects provided by plugins with given target and type * A sequences of all objects provided by plugins with given target and type
*/ */
inline fun <reified T : Any> Context.members(): Sequence<T> = members<T>(Types[T::class]) inline fun <reified T : Any> Context.content(): Map<Name, T> = content<T>(Types[T::class])

View File

@ -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() 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)) fun NameToken.asName() = Name(listOf(this))
val EmptyName = Name(emptyList()) val EmptyName = Name(emptyList())

View File

@ -4,11 +4,9 @@ import hep.dataforge.context.Context
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.output.Output import hep.dataforge.output.Output
import hep.dataforge.output.TextRenderer 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.output.html.HtmlBuilder.Companion.HTML_CONVERTER_TYPE
import hep.dataforge.provider.Type import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll import hep.dataforge.provider.top
import hep.dataforge.provider.provideAllByType
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.html.TagConsumer import kotlinx.html.TagConsumer
@ -29,7 +27,7 @@ class HtmlOutput<T : Any>(override val context: Context, private val consumer: T
} else { } else {
val value = cache[obj::class] val value = cache[obj::class]
if (value == null) { if (value == null) {
val answer = context.provideAllByType<HtmlBuilder<*>>() val answer = context.top<HtmlBuilder<*>>().values
.filter { it.type.isInstance(obj) }.firstOrNull() .filter { it.type.isInstance(obj) }.firstOrNull()
if (answer != null) { if (answer != null) {
cache[obj::class] = answer cache[obj::class] = answer

View File

@ -1,10 +1,10 @@
package hep.dataforge.output package hep.dataforge.output
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.provider.Type import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll import hep.dataforge.provider.top
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -21,8 +21,8 @@ class TextOutput(override val context: Context, private val output: kotlinx.io.c
} else { } else {
val value = cache[obj::class] val value = cache[obj::class]
if (value == null) { if (value == null) {
val answer = context.provideAll(TEXT_RENDERER_TYPE).filterIsInstance<TextRenderer>() val answer =
.filter { it.type.isInstance(obj) }.firstOrNull() context.top<TextRenderer>(TEXT_RENDERER_TYPE).values.firstOrNull { it.type.isInstance(obj) }
if (answer != null) { if (answer != null) {
cache[obj::class] = answer cache[obj::class] = answer
answer answer

View File

@ -8,6 +8,7 @@ import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.names.EmptyName import hep.dataforge.names.EmptyName
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.get
import hep.dataforge.names.isEmpty 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() { class TaskModelDependency(val name: String, val meta: Meta, val placement: Name = EmptyName) : Dependency() {
override fun apply(workspace: Workspace): DataNode<Any> { override fun apply(workspace: Workspace): DataNode<Any> {
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") if (task.isTerminal) TODO("Support terminal task")
val result = workspace.run(task, meta) val result = workspace.run(task, meta)
return if (placement.isEmpty()) { return if (placement.isEmpty()) {

View File

@ -2,9 +2,11 @@ package hep.dataforge.workspace
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.context.members
import hep.dataforge.data.DataNode import hep.dataforge.data.DataNode
import hep.dataforge.meta.Meta 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<String, Meta>, override val targets: Map<String, Meta>,
tasks: Collection<Task<Any>> tasks: Collection<Task<Any>>
) : Workspace { ) : Workspace {
override val tasks: Map<String, Task<*>> by lazy { override val tasks: Map<Name, Task<*>> by lazy {
(context.members<Task<*>>(Task.TYPE) + tasks).associate { it.name to it } context.top<Task<*>>(Task.TYPE) + tasks.associate { it.name.toName() to it }
} }
companion object { companion object {

View File

@ -27,22 +27,22 @@ interface Workspace : ContextAware, Provider {
/** /**
* All tasks associated with the workspace * All tasks associated with the workspace
*/ */
val tasks: Map<String, Task<*>> val tasks: Map<Name, Task<*>>
override fun provideTop(target: String, name: Name): Any? { override fun provideTop(target: String, name: Name): Any? {
return when (target) { return when (target) {
"target", Meta.TYPE -> targets[name.toString()] "target", Meta.TYPE -> targets[name.toString()]
Task.TYPE -> tasks[name.toString()] Task.TYPE -> tasks[name]
Data.TYPE -> data[name] Data.TYPE -> data[name]
DataNode.TYPE -> data.getNode(name) DataNode.TYPE -> data.getNode(name)
else -> null else -> null
} }
} }
override fun listTop(target: String): Sequence<Name> { override fun listNames(target: String): Sequence<Name> {
return when (target) { return when (target) {
"target", Meta.TYPE -> targets.keys.asSequence().map { it.toName() } "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 } Data.TYPE -> data.data().map { it.first }
DataNode.TYPE -> data.nodes().map { it.first } DataNode.TYPE -> data.nodes().map { it.first }
else -> emptySequence() else -> emptySequence()
@ -85,10 +85,10 @@ fun Workspace.run(task: Task<*>, target: String): DataNode<Any> {
fun Workspace.run(task: String, target: String) = 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) = 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 = {}) = fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}) =
run(task, buildMeta(block)) run(task, buildMeta(block))