IO update

This commit is contained in:
Alexander Nozik 2019-01-27 20:54:28 +03:00
parent 4cafac1f1b
commit 2d8810110e
12 changed files with 178 additions and 52 deletions

View File

@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
buildscript { buildscript {
val kotlinVersion: String by rootProject.extra("1.3.20") val kotlinVersion: String by rootProject.extra("1.3.20")
val ioVersion: String by rootProject.extra("0.1.2") val ioVersion: String by rootProject.extra("0.1.4")
val coroutinesVersion: String by rootProject.extra("1.1.1") val coroutinesVersion: String by rootProject.extra("1.1.1")
val serializationVersion: String by rootProject.extra("0.9.1") val serializationVersion: String by rootProject.extra("0.9.1")

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.provider.Provider import hep.dataforge.provider.Provider
import hep.dataforge.provider.Types
import hep.dataforge.provider.provideAll import hep.dataforge.provider.provideAll
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -94,8 +95,8 @@ interface Context : Named, MetaRepr, Provider, CoroutineScope {
/** /**
* 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.list(target: String): Sequence<T> { inline fun <reified T : Any> Context.provideAll(target: String = Types[T::class]): Sequence<T> {
return plugins.asSequence().flatMap { provideAll(target) }.mapNotNull { it as? T } return plugins.asSequence().flatMap { it.provideAll(target) }.filterIsInstance<T>()
} }
/** /**

View File

@ -44,6 +44,8 @@ data class PluginTag(
companion object { companion object {
const val DATAFORGE_GROUP = "hep.dataforge"
/** /**
* Build new PluginTag from standard string representation * Build new PluginTag from standard string representation
* *

View File

@ -85,5 +85,13 @@ inline fun <reified T : Any> Provider.provide(target: String, name: String): T?
* [Sequence] of all elements with given target * [Sequence] of all elements with given target
*/ */
fun Provider.provideAll(target: String): Sequence<Any> { fun Provider.provideAll(target: String): Sequence<Any> {
return listTop(target).map { it -> provideTop(target, it) ?: error("The element $it is declared but not provided") } return listTop(target).map { provideTop(target, it) ?: error("The element $it is declared but not provided") }
}
/**
* Provide an object with given name inferring target from its type using [Type] annotation
*/
inline fun <reified T : Any> Provider.provideByType(name: String): T? {
val target = Types[T::class]
return provide(target, name)
} }

View File

@ -0,0 +1,26 @@
package hep.dataforge.provider
import kotlin.reflect.KClass
/**
* A text label for internal DataForge type classification. Alternative for mime container type.
*
* The DataForge type notation presumes that type `A.B.C` is the subtype of `A.B`
*/
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
annotation class Type(val id: String)
/**
* Utils to get type of classes and objects
*/
object Types {
operator fun get(cl: KClass<*>): String {
return cl.annotations.filterIsInstance<Type>().firstOrNull()?.id ?: cl.simpleName ?: ""
}
operator fun get(obj: Any): String {
return get(obj::class)
}
}

View File

@ -1,32 +0,0 @@
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
repositories {
jcenter()
}
kotlin {
targets {
fromPreset(presets.jvm, 'jvm')
fromPreset(presets.js, 'js')
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
//fromPreset(presets.iosX64, 'ios')
}
sourceSets {
commonMain {
dependencies {
api project(":dataforge-context")
api project(":dataforge-meta-io")
}
}
jvmMain {
dependencies {
}
}
}
}

View File

@ -0,0 +1,20 @@
plugins {
kotlin("multiplatform")
}
repositories {
jcenter()
}
kotlin {
jvm()
js()
sourceSets {
val commonMain by getting{
dependencies {
api(project(":dataforge-context"))
api(project(":dataforge-meta-io"))
}
}
}
}

View File

@ -1,10 +1,14 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Plugin import hep.dataforge.context.Plugin
import hep.dataforge.context.PluginTag
import hep.dataforge.context.PluginTag.Companion.DATAFORGE_GROUP
import hep.dataforge.meta.EmptyMeta import hep.dataforge.meta.EmptyMeta
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.names.EmptyName import hep.dataforge.names.EmptyName
import hep.dataforge.names.Name import hep.dataforge.names.Name
import kotlinx.coroutines.CoroutineDispatcher
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -38,3 +42,22 @@ inline fun <reified T : Any> OutputManager.typed(
): Output<T> { ): Output<T> {
return typed(T::class, name, stage, meta) return typed(T::class, name, stage, meta)
} }
/**
* System console output.
* The [ConsoleOutput] is used when no other [OutputManager] is provided.
*/
expect val ConsoleOutput: Output<Any>
object ConsoleOutputManager : AbstractPlugin(), OutputManager {
override val tag: PluginTag = PluginTag("output.console", group = DATAFORGE_GROUP)
override fun get(name: Name, stage: Name, meta: Meta): Output<Any> = ConsoleOutput
override fun <T : Any> typed(type: KClass<T>, name: Name, stage: Name, meta: Meta): Output<T> = ConsoleOutput
}
/**
* A dispatcher for output tasks.
*/
expect val OutputDispatcher : CoroutineDispatcher

View File

@ -0,0 +1,59 @@
package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.context.provideAll
import hep.dataforge.meta.Meta
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
class TextOutput(override val context: Context, private val output: kotlinx.io.core.Output) : Output<Any> {
private val cache = HashMap<KClass<*>, TextRenderer>()
/**
* Find the first [TextRenderer] matching the given object type.
*/
override fun render(obj: Any, meta: Meta) {
val renderer: TextRenderer = if (obj is CharSequence) {
DefaultTextRenderer
} else {
val value = cache[obj::class]
if (value == null) {
val answer = context.provideAll<TextRenderer>().filter { it.type.isInstance(obj) }.firstOrNull()
if (answer != null) {
cache[obj::class] = answer
answer
} else {
DefaultTextRenderer
}
} else {
value
}
}
context.launch(OutputDispatcher) {
renderer.run { output.render(obj) }
}
}
}
interface TextRenderer {
/**
* The priority of this renderer compared to other renderers
*/
val priority: Int
/**
* The type of the content served by this renderer
*/
val type: KClass<*>
suspend fun kotlinx.io.core.Output.render(obj: Any)
}
object DefaultTextRenderer : TextRenderer {
override val priority: Int = Int.MAX_VALUE
override val type: KClass<*> = Any::class
override suspend fun kotlinx.io.core.Output.render(obj: Any) {
append(obj.toString())
append('\n')
}
}

View File

@ -0,0 +1,22 @@
package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.meta.Meta
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
/**
* System console output.
* The [ConsoleOutput] is used when no other [OutputManager] is provided.
*/
actual val ConsoleOutput: Output<Any> = object : Output<Any> {
override fun render(obj: Any, meta: Meta) {
println(obj)
}
override val context: Context get() = Global
}
actual val OutputDispatcher: CoroutineDispatcher = Dispatchers.Default

View File

@ -0,0 +1,13 @@
package hep.dataforge.io
import hep.dataforge.context.Global
import kotlinx.coroutines.Dispatchers
import kotlinx.io.streams.asOutput
/**
* System console output.
* The [ConsoleOutput] is used when no other [OutputManager] is provided.
*/
actual val ConsoleOutput: Output<Any> = TextOutput(Global, System.out.asOutput())
actual val OutputDispatcher = Dispatchers.IO

View File

@ -1,16 +0,0 @@
package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.meta.Meta
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class TextOutput(override val context: Context, private val output: kotlinx.io.core.Output) : Output<Any> {
override fun render(obj: Any, meta: Meta) {
context.launch(Dispatchers.IO) {
output.append(obj.toString())
output.append('\n')
}
}
}