From 80fab0ac4f5149a8b82d169c0c74eab4fdf06488 Mon Sep 17 00:00:00 2001 From: Sergey Okatov Date: Sun, 7 Aug 2022 22:30:45 +0500 Subject: [PATCH] 1. Interface structure is refactored 2. subChain handler is added --- README.md | 2 +- build.gradle.kts | 2 +- gradle.properties | 2 +- src/commonMain/kotlin/base/BaseCorChainDsl.kt | 8 +- .../kotlin/base/BaseCorWorkerDsl.kt | 2 +- src/commonMain/kotlin/cor.kt | 9 ++- src/commonMain/kotlin/handlers/Chain.kt | 6 +- src/commonMain/kotlin/handlers/Loop.kt | 8 +- src/commonMain/kotlin/handlers/Parallel.kt | 6 +- src/commonMain/kotlin/handlers/SubChain.kt | 75 +++++++++++++++++++ src/commonMain/kotlin/handlers/Worker.kt | 9 +-- src/commonTest/kotlin/CorBaseTest.kt | 17 +---- src/commonTest/kotlin/CorExceptionTest.kt | 1 + src/commonTest/kotlin/CorSubChainTest.kt | 46 ++++++++++++ src/commonTest/kotlin/CorTest.kt | 2 + src/commonTest/kotlin/LoopCorBaseTest.kt | 2 + src/commonTest/kotlin/helper/CorStatuses.kt | 7 ++ src/commonTest/kotlin/helper/TestContext.kt | 9 +++ .../kotlin/helper/TestSubContext.kt | 6 ++ 19 files changed, 178 insertions(+), 41 deletions(-) create mode 100644 src/commonMain/kotlin/handlers/SubChain.kt create mode 100644 src/commonTest/kotlin/CorSubChainTest.kt create mode 100644 src/commonTest/kotlin/helper/CorStatuses.kt create mode 100644 src/commonTest/kotlin/helper/TestContext.kt create mode 100644 src/commonTest/kotlin/helper/TestSubContext.kt diff --git a/README.md b/README.md index 98a7285..31b3faa 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ dependencies { ``` #### **`gradle.properties`** ```properties -kotlinCorVersion=0.4.0+ +kotlinCorVersion=0.5.0+ ``` ## Usage diff --git a/build.gradle.kts b/build.gradle.kts index 68066be..26d7afc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "com.crowdproj.kotlin.cor" -version = "0.4.0" +version = "0.5.0" repositories { mavenCentral() diff --git a/gradle.properties b/gradle.properties index 4ab53ff..2c548e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -kotlinVersion=1.7.0 +kotlinVersion=1.7.10 coroutinesVersion=1.6.3 # -native-mt diff --git a/src/commonMain/kotlin/base/BaseCorChainDsl.kt b/src/commonMain/kotlin/base/BaseCorChainDsl.kt index 9c51da1..d922f54 100644 --- a/src/commonMain/kotlin/base/BaseCorChainDsl.kt +++ b/src/commonMain/kotlin/base/BaseCorChainDsl.kt @@ -2,17 +2,17 @@ package com.crowdproj.kotlin.cor.base import com.crowdproj.kotlin.cor.* -abstract class BaseCorChainDsl( +abstract class BaseCorChainDsl( override var title: String = "", override var description: String = "", - protected val workers: MutableList> = mutableListOf(), + protected val workers: MutableList> = mutableListOf(), protected var blockOn: suspend T.() -> Boolean = { true }, protected var blockExcept: suspend T.(e: Throwable) -> Unit = { e: Throwable -> throw e }, -) : ICorChainDsl { +) : ICorExecDsl, ICorOnDsl, ICorExceptDsl, ICorAddExecDsl { abstract override fun build(): ICorExec - override fun add(worker: ICorExecDsl) { + override fun add(worker: ICorExecDsl) { workers.add(worker) } diff --git a/src/commonMain/kotlin/base/BaseCorWorkerDsl.kt b/src/commonMain/kotlin/base/BaseCorWorkerDsl.kt index 554fe58..3702b7f 100644 --- a/src/commonMain/kotlin/base/BaseCorWorkerDsl.kt +++ b/src/commonMain/kotlin/base/BaseCorWorkerDsl.kt @@ -8,7 +8,7 @@ abstract class BaseCorWorkerDsl( protected var blockOn: suspend T.() -> Boolean = { true }, protected var blockHandle: suspend T.() -> Unit = {}, protected var blockExcept: suspend T.(e: Throwable) -> Unit = { e: Throwable -> throw e }, -) : ICorWorkerDsl { +) : ICorExecDsl, ICorOnDsl, ICorExceptDsl, ICorHandleDsl { abstract override fun build(): ICorExec diff --git a/src/commonMain/kotlin/cor.kt b/src/commonMain/kotlin/cor.kt index 93e59fe..c6f368e 100644 --- a/src/commonMain/kotlin/cor.kt +++ b/src/commonMain/kotlin/cor.kt @@ -9,16 +9,19 @@ interface ICorExecDsl { fun build(): ICorExec } -interface ICorHandlerDsl { +interface ICorOnDsl { fun on(function: suspend T.() -> Boolean) +} + +interface ICorExceptDsl { fun except(function: suspend T.(e: Throwable) -> Unit) } -interface ICorChainDsl : ICorExecDsl, ICorHandlerDsl { +interface ICorAddExecDsl { fun add(worker: ICorExecDsl) } -interface ICorWorkerDsl : ICorExecDsl, ICorHandlerDsl { +interface ICorHandleDsl { fun handle(function: suspend T.() -> Unit) } diff --git a/src/commonMain/kotlin/handlers/Chain.kt b/src/commonMain/kotlin/handlers/Chain.kt index d1f0720..f10ab76 100644 --- a/src/commonMain/kotlin/handlers/Chain.kt +++ b/src/commonMain/kotlin/handlers/Chain.kt @@ -1,13 +1,13 @@ package com.crowdproj.kotlin.cor.handlers import com.crowdproj.kotlin.cor.CorDslMarker -import com.crowdproj.kotlin.cor.ICorChainDsl +import com.crowdproj.kotlin.cor.ICorAddExecDsl import com.crowdproj.kotlin.cor.ICorExec import com.crowdproj.kotlin.cor.base.BaseCorChain import com.crowdproj.kotlin.cor.base.BaseCorChainDsl @CorDslMarker -fun ICorChainDsl.chain(function: CorChainDsl.() -> Unit) { +fun ICorAddExecDsl.chain(function: CorChainDsl.() -> Unit) { add(CorChainDsl().apply(function)) } @@ -34,7 +34,7 @@ class CorChain( * The chains are executed sequentially. */ @CorDslMarker -class CorChainDsl() : BaseCorChainDsl() { +class CorChainDsl() : BaseCorChainDsl() { override fun build(): ICorExec = CorChain( title = title, description = description, diff --git a/src/commonMain/kotlin/handlers/Loop.kt b/src/commonMain/kotlin/handlers/Loop.kt index 88f5c14..ebe7073 100644 --- a/src/commonMain/kotlin/handlers/Loop.kt +++ b/src/commonMain/kotlin/handlers/Loop.kt @@ -1,13 +1,13 @@ package com.crowdproj.kotlin.cor.handlers import com.crowdproj.kotlin.cor.CorDslMarker -import com.crowdproj.kotlin.cor.ICorChainDsl +import com.crowdproj.kotlin.cor.ICorAddExecDsl import com.crowdproj.kotlin.cor.ICorExec import com.crowdproj.kotlin.cor.base.BaseCorChain import com.crowdproj.kotlin.cor.base.BaseCorChainDsl @CorDslMarker -fun ICorChainDsl.loopWhile( +fun ICorAddExecDsl.loopWhile( function: CorLoopDsl.() -> Unit ) { add( @@ -16,7 +16,7 @@ fun ICorChainDsl.loopWhile( } @CorDslMarker -fun ICorChainDsl.loopUntil( +fun ICorAddExecDsl.loopUntil( function: CorLoopDsl.() -> Unit ) { add( @@ -72,7 +72,7 @@ class CorLoop( class CorLoopDsl( private val checkBefore: Boolean, var blockCheck: suspend T.() -> Boolean = { true }, -) : BaseCorChainDsl() { +) : BaseCorChainDsl() { override fun build(): ICorExec = CorLoop( checkBefore, title = title, diff --git a/src/commonMain/kotlin/handlers/Parallel.kt b/src/commonMain/kotlin/handlers/Parallel.kt index 3486ce2..c1644aa 100644 --- a/src/commonMain/kotlin/handlers/Parallel.kt +++ b/src/commonMain/kotlin/handlers/Parallel.kt @@ -1,7 +1,7 @@ package com.crowdproj.kotlin.cor.handlers import com.crowdproj.kotlin.cor.CorDslMarker -import com.crowdproj.kotlin.cor.ICorChainDsl +import com.crowdproj.kotlin.cor.ICorAddExecDsl import com.crowdproj.kotlin.cor.ICorExec import com.crowdproj.kotlin.cor.base.BaseCorChain import com.crowdproj.kotlin.cor.base.BaseCorChainDsl @@ -9,7 +9,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch @CorDslMarker -fun ICorChainDsl.parallel(function: CorParallelDsl.() -> Unit) { +fun ICorAddExecDsl.parallel(function: CorParallelDsl.() -> Unit) { add(CorParallelDsl().apply(function)) } @@ -40,7 +40,7 @@ class CorParallel( * Chains are started simultaneously and executed in parallel. */ @CorDslMarker -class CorParallelDsl(): BaseCorChainDsl() { +class CorParallelDsl(): BaseCorChainDsl() { override fun build(): ICorExec = CorParallel( title = title, description = description, diff --git a/src/commonMain/kotlin/handlers/SubChain.kt b/src/commonMain/kotlin/handlers/SubChain.kt new file mode 100644 index 0000000..6fbe198 --- /dev/null +++ b/src/commonMain/kotlin/handlers/SubChain.kt @@ -0,0 +1,75 @@ +package com.crowdproj.kotlin.cor.handlers + +import com.crowdproj.kotlin.cor.CorDslMarker +import com.crowdproj.kotlin.cor.ICorAddExecDsl +import com.crowdproj.kotlin.cor.ICorExec +import com.crowdproj.kotlin.cor.base.BaseCorChain +import com.crowdproj.kotlin.cor.base.BaseCorChainDsl +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch + +@CorDslMarker +fun ICorAddExecDsl.subChain(function: CorSubChainDsl.() -> Unit) { + add(CorSubChainDsl().apply(function)) +} + +class CorSubChain( + private val execs: List>, + title: String, + description: String = "", + blockOn: suspend T.() -> Boolean = { true }, + private val blockSplit: suspend T.() -> Flow, + private val blockJoin: suspend T.(K) -> Unit, + blockExcept: suspend T.(Throwable) -> Unit = {}, + private val buffer: Int = 1, +) : BaseCorChain( + title = title, + description = description, + blockOn = blockOn, + blockExcept = blockExcept +) { + + override suspend fun handle(context: T): Unit = coroutineScope { + context + .blockSplit() + .onEach { subCtx -> execs.map{ launch { it.exec(subCtx) } }.forEach { it.join() } } + .buffer(buffer) + .collect { context.blockJoin(it) } + } +} + +/** + * DLS is the execution context of multiple chains. + * It can be expanded by other chains. + */ +@CorDslMarker +class CorSubChainDsl( +): BaseCorChainDsl() { + private var blockSplit: suspend T.() -> Flow = { emptyFlow() } + private var blockJoin: suspend T.(K) -> Unit = {} + private var bufferSize: Int = 0 + + fun buffer(size: Int) { + bufferSize = size + } + + fun split(funSplit: suspend T.() -> Flow) { + blockSplit = funSplit + } + + fun join(funJoin: suspend T.(K) -> Unit) { + blockJoin = funJoin + } + + override fun build(): ICorExec = CorSubChain( + title = title, + description = description, + execs = workers.map { it.build() }.toList(), + blockOn = blockOn, + blockExcept = blockExcept, + blockSplit = blockSplit, + blockJoin = blockJoin, + buffer = bufferSize + ) +} diff --git a/src/commonMain/kotlin/handlers/Worker.kt b/src/commonMain/kotlin/handlers/Worker.kt index 07ad327..af32f42 100644 --- a/src/commonMain/kotlin/handlers/Worker.kt +++ b/src/commonMain/kotlin/handlers/Worker.kt @@ -1,13 +1,10 @@ package com.crowdproj.kotlin.cor.handlers -import com.crowdproj.kotlin.cor.CorDslMarker -import com.crowdproj.kotlin.cor.ICorChainDsl -import com.crowdproj.kotlin.cor.ICorExec -import com.crowdproj.kotlin.cor.ICorWorker +import com.crowdproj.kotlin.cor.* import com.crowdproj.kotlin.cor.base.BaseCorWorkerDsl @CorDslMarker -fun ICorChainDsl.worker( +fun ICorAddExecDsl.worker( function: CorWorkerDsl.() -> Unit ) { add( @@ -16,7 +13,7 @@ fun ICorChainDsl.worker( } @CorDslMarker -fun ICorChainDsl.worker( +fun ICorAddExecDsl.worker( title: String, description: String = "", function: suspend T.() -> Unit diff --git a/src/commonTest/kotlin/CorBaseTest.kt b/src/commonTest/kotlin/CorBaseTest.kt index 9307a7a..1218991 100644 --- a/src/commonTest/kotlin/CorBaseTest.kt +++ b/src/commonTest/kotlin/CorBaseTest.kt @@ -3,6 +3,8 @@ package com.crowdproj.kotlin.cor import com.crowdproj.kotlin.cor.handlers.chain import com.crowdproj.kotlin.cor.handlers.parallel import com.crowdproj.kotlin.cor.handlers.worker +import com.crowdproj.kotlin.cor.helper.CorStatuses +import com.crowdproj.kotlin.cor.helper.TestContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -56,20 +58,7 @@ class CorBaseTest { } } -private fun ICorChainDsl.printResult() = worker(title = "Print example") { +private fun ICorAddExecDsl.printResult() = worker(title = "Print example") { println("some = $some") } -data class TestContext( - var status: CorStatuses = CorStatuses.NONE, - var some: Int = Int.MIN_VALUE, - var text: String = "", -) { - -} - -enum class CorStatuses { - NONE, - RUNNING, - FAILING, -} diff --git a/src/commonTest/kotlin/CorExceptionTest.kt b/src/commonTest/kotlin/CorExceptionTest.kt index f41e9ba..d768398 100644 --- a/src/commonTest/kotlin/CorExceptionTest.kt +++ b/src/commonTest/kotlin/CorExceptionTest.kt @@ -2,6 +2,7 @@ package com.crowdproj.kotlin.cor import com.crowdproj.kotlin.cor.handlers.chain import com.crowdproj.kotlin.cor.handlers.worker +import com.crowdproj.kotlin.cor.helper.TestContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlin.js.JsName diff --git a/src/commonTest/kotlin/CorSubChainTest.kt b/src/commonTest/kotlin/CorSubChainTest.kt new file mode 100644 index 0000000..acb972d --- /dev/null +++ b/src/commonTest/kotlin/CorSubChainTest.kt @@ -0,0 +1,46 @@ +package com.crowdproj.kotlin.cor + +import com.crowdproj.kotlin.cor.handlers.subChain +import com.crowdproj.kotlin.cor.handlers.worker +import com.crowdproj.kotlin.cor.helper.CorStatuses +import com.crowdproj.kotlin.cor.helper.TestContext +import com.crowdproj.kotlin.cor.helper.TestSubContext +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(ExperimentalCoroutinesApi::class) +class CorSubChainTest { + @Test + fun createCor() = runTest { + val ctx = TestContext() + chain.exec(ctx) + assertEquals(CorStatuses.RUNNING, ctx.status) + assertEquals(65, ctx.some) + } + + companion object { + val chain = rootChain { + worker("status") { status = CorStatuses.RUNNING } + worker("init") { + some = 0 + } + subChain { + buffer(20) + on { status == CorStatuses.RUNNING } + split { (1..10).asFlow().map { TestSubContext(temp = it) } } + worker { + handle { + temp ++ + } + } + join { sub: TestSubContext -> + some += sub.temp + } + } + }.build() + } +} diff --git a/src/commonTest/kotlin/CorTest.kt b/src/commonTest/kotlin/CorTest.kt index e6620ce..fbd1eb3 100644 --- a/src/commonTest/kotlin/CorTest.kt +++ b/src/commonTest/kotlin/CorTest.kt @@ -1,5 +1,7 @@ package com.crowdproj.kotlin.cor +import com.crowdproj.kotlin.cor.helper.CorStatuses +import com.crowdproj.kotlin.cor.helper.TestContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlin.test.Test diff --git a/src/commonTest/kotlin/LoopCorBaseTest.kt b/src/commonTest/kotlin/LoopCorBaseTest.kt index 463227c..01cf75a 100644 --- a/src/commonTest/kotlin/LoopCorBaseTest.kt +++ b/src/commonTest/kotlin/LoopCorBaseTest.kt @@ -3,6 +3,8 @@ package com.crowdproj.kotlin.cor import com.crowdproj.kotlin.cor.handlers.loopUntil import com.crowdproj.kotlin.cor.handlers.loopWhile import com.crowdproj.kotlin.cor.handlers.worker +import com.crowdproj.kotlin.cor.helper.CorStatuses +import com.crowdproj.kotlin.cor.helper.TestContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlin.test.Test diff --git a/src/commonTest/kotlin/helper/CorStatuses.kt b/src/commonTest/kotlin/helper/CorStatuses.kt new file mode 100644 index 0000000..d484467 --- /dev/null +++ b/src/commonTest/kotlin/helper/CorStatuses.kt @@ -0,0 +1,7 @@ +package com.crowdproj.kotlin.cor.helper + +enum class CorStatuses { + NONE, + RUNNING, + FAILING, +} diff --git a/src/commonTest/kotlin/helper/TestContext.kt b/src/commonTest/kotlin/helper/TestContext.kt new file mode 100644 index 0000000..34a9a93 --- /dev/null +++ b/src/commonTest/kotlin/helper/TestContext.kt @@ -0,0 +1,9 @@ +package com.crowdproj.kotlin.cor.helper + +data class TestContext( + var status: CorStatuses = CorStatuses.NONE, + var some: Int = Int.MIN_VALUE, + var text: String = "", +) { + +} diff --git a/src/commonTest/kotlin/helper/TestSubContext.kt b/src/commonTest/kotlin/helper/TestSubContext.kt new file mode 100644 index 0000000..d144156 --- /dev/null +++ b/src/commonTest/kotlin/helper/TestSubContext.kt @@ -0,0 +1,6 @@ +package com.crowdproj.kotlin.cor.helper + +data class TestSubContext( + var temp: Int = Int.MIN_VALUE, + var str: String = "", +)