diff --git a/.idea/runConfigurations/_allTests.xml b/.idea/runConfigurations/_allTests.xml new file mode 100644 index 000000000..4a728aa1d --- /dev/null +++ b/.idea/runConfigurations/_allTests.xml @@ -0,0 +1,29 @@ + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2dbf45aa0..f4c70c6ec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,6 +74,10 @@ subprojects { if (hasKtP()) { // apply(plugin = "io.gitlab.arturbosch.detekt") applyDetekt() + if ("gradle" !in name) { + useK2() + logger.info("Enable K2 for {}", this) + } } } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 34a75b30f..2dab0ad5b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -58,3 +58,15 @@ idea { isDownloadSources = true } } + +// tasks.withType(KotlinCompile::class.java).configureEach { +// kotlinOptions.languageVersion = "1.9" +// } + +// val compileKotlin: KotlinCompile by tasks +// compileKotlin.kotlinOptions.freeCompilerArgs += listOf( +// "-Xjvm-default=all", +// // "-opt-in=kotlin.RequiresOptIn", +// // see https://youtrack.jetbrains.com/issue/KTIJ-21563 +// "-Xskip-prerelease-check", +// ) diff --git a/buildSrc/src/main/kotlin/K2Config.kt b/buildSrc/src/main/kotlin/K2Config.kt new file mode 100644 index 000000000..5bb81f565 --- /dev/null +++ b/buildSrc/src/main/kotlin/K2Config.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * Project https://github.com/simple-robot/simpler-robot + * Email ForteScarlet@163.com + * + * This file is part of the Simple Robot Library. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + * + */ + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.withType + + +fun Project.useK2(languageVersion: String = "2.0") { + tasks.withType { + kotlinOptions { + // useK2 + this.languageVersion = languageVersion + } + } +} diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt index 57c3b7276..cf032fac7 100644 --- a/buildSrc/src/main/kotlin/P.kt +++ b/buildSrc/src/main/kotlin/P.kt @@ -81,7 +81,7 @@ sealed class P(override val group: String) : ProjectDetail() { val versionWithoutSnapshot: Version init { - val mainVersion = version(4, 0, 0) - version("dev14") + val mainVersion = version(4, 0, 0) - version("dev15") fun initVersionWithoutSnapshot(status: Version?): Version = if (status == null) { mainVersion diff --git a/buildSrc/src/main/kotlin/simbot.dokka-multi-module.gradle.kts b/buildSrc/src/main/kotlin/simbot.dokka-multi-module.gradle.kts index 8a826ffca..95f99ec6b 100644 --- a/buildSrc/src/main/kotlin/simbot.dokka-multi-module.gradle.kts +++ b/buildSrc/src/main/kotlin/simbot.dokka-multi-module.gradle.kts @@ -28,7 +28,7 @@ import java.time.Year /* - 使用在根配置,配置dokka多模块 +使用在根配置,配置dokka多模块 */ plugins { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e8bcbf31..7491df2b7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,12 +8,13 @@ spring-boot-v3 = "3.2.1" openjdk-jmh = "1.36" ktor = "2.3.7" slf4j = "2.0.7" -ksp = "1.9.22-1.0.16" +#ksp = "1.9.22-1.0.16" +ksp = "1.9.22-1.0.17" # https://square.github.io/kotlinpoet/ kotlinPoet = "1.15.3" reactor = "3.6.2" # -suspendTransform = "0.6.0" +suspendTransform = "0.7.0-beta1" suspendReversal = "0.2.0" gradleCommon = "0.2.0" diff --git a/simbot-api/build.gradle.kts b/simbot-api/build.gradle.kts index c1f11e7ae..3d62cc1e8 100644 --- a/simbot-api/build.gradle.kts +++ b/simbot-api/build.gradle.kts @@ -114,6 +114,7 @@ kotlin { implementation(libs.ktor.client.core) implementation(kotlin("test-junit5")) + implementation(kotlin("reflect")) implementation(libs.ktor.client.cio) } } diff --git a/simbot-api/src/jvmMain/kotlin/love/forte/simbot/application/ApplicationFactory.jvm.kt b/simbot-api/src/jvmMain/kotlin/love/forte/simbot/application/ApplicationFactory.jvm.kt index 94cf40b9d..8da09c531 100644 --- a/simbot-api/src/jvmMain/kotlin/love/forte/simbot/application/ApplicationFactory.jvm.kt +++ b/simbot-api/src/jvmMain/kotlin/love/forte/simbot/application/ApplicationFactory.jvm.kt @@ -60,7 +60,9 @@ public fun interface JBlockingApplicationLauncher { } private class JBlockingApplicationLauncherImpl( - private val handler: JBlockingApplicationLauncher, + // TODO private: + // e: file:///G:/code/simbot/simbot-api/src/jvmMain/kotlin/love/forte/simbot/application/ApplicationFactory.jvm.kt:78:35 Cannot access 'val handler: JBlockingApplicationLauncher': it is private/*private to this*/ in 'love/forte/simbot/application/JBlockingApplicationLauncherImpl' + val handler: JBlockingApplicationLauncher, private val handlerContext: CoroutineContext ) : ApplicationLauncher { override suspend fun launch(): A { @@ -73,8 +75,8 @@ private class JBlockingApplicationLauncherImpl( if (this === other) return true if (other !is JBlockingApplicationLauncherImpl<*>) return false - if (handler != other.handler) return false if (handlerContext != other.handlerContext) return false + if (this.handler != other.handler) return false return true } diff --git a/simbot-api/src/jvmTest/kotlin/SuspendTransformTests.kt b/simbot-api/src/jvmTest/kotlin/SuspendTransformTests.kt new file mode 100644 index 000000000..144596408 --- /dev/null +++ b/simbot-api/src/jvmTest/kotlin/SuspendTransformTests.kt @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * Project https://github.com/simple-robot/simpler-robot + * Email ForteScarlet@163.com + * + * This file is part of the Simple Robot Library. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + * + */ +import love.forte.simbot.suspendrunner.ST +import love.forte.simbot.suspendrunner.STP +import love.forte.simbot.suspendrunner.reserve.SuspendReserve +import java.lang.reflect.Modifier +import java.util.concurrent.CompletableFuture +import kotlin.reflect.KTypeParameter +import kotlin.reflect.full.memberProperties +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + + +@ST +interface STTrans1 { + suspend fun run1() + suspend fun run1(value: String): String +} + +@STP +interface STPTrans1 { + suspend fun run1(): Int + suspend fun run2(): String +} + +interface STTrans2 { + @ST(blockingSuffix = "Bk", asyncSuffix = "Ay", reserveSuffix = "Rs") + suspend fun run1() + + @ST(blockingSuffix = "Bk", asyncSuffix = "Ay", reserveSuffix = "Rs") + suspend fun run1(value: String): String +} + +interface STPTrans2 { + @STP(blockingSuffix = "Bk", asyncSuffix = "Ay", reserveSuffix = "Rs") + suspend fun run1(): Int + + @STP(blockingSuffix = "Bk", asyncSuffix = "Ay", reserveSuffix = "Rs") + suspend fun run2(): String +} + +interface STTrans3 { + @ST( + blockingBaseName = "apply1", + blockingSuffix = "Bk", + asyncBaseName = "apply1", + asyncSuffix = "Ay", + reserveBaseName = "apply1", + reserveSuffix = "Rs" + ) + suspend fun run1() + + @ST( + blockingBaseName = "apply1", + blockingSuffix = "Bk", + asyncBaseName = "apply1", + asyncSuffix = "Ay", + reserveBaseName = "apply1", + reserveSuffix = "Rs" + ) + suspend fun run1(value: String): String +} + +interface STPTrans3 { + @STP( + blockingBaseName = "apply1", + blockingSuffix = "Bk", + asyncBaseName = "apply1", + asyncSuffix = "Ay", + reserveBaseName = "apply1", + reserveSuffix = "Rs" + ) + suspend fun run1(): Int + + @STP( + blockingBaseName = "apply2", + blockingSuffix = "Bk", + asyncBaseName = "apply2", + asyncSuffix = "Ay", + reserveBaseName = "apply2", + reserveSuffix = "Rs" + ) + suspend fun run2(): String +} + +open class Foo +open class Bar : Foo() + +@STP +interface ITypedTrans1 { + suspend fun value(): T +} + +@STP +interface TypedTrans1Impl : ITypedTrans1 { + override suspend fun value(): T +} + +/** + * + * @author ForteScarlet + */ +class SuspendTransformTests { + + @Test + fun `interface suspend trans function test`() { + with(STTrans1::class.java) { + val blockingMethod = getMethod("run1Blocking") + val asyncMethod = getMethod("run1Async") + val reserveMethod = getMethod("run1Reserve") + + assertEquals(Void.TYPE, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + + with(STTrans1::class.java) { + val blockingMethod = getMethod("run1Blocking", String::class.java) + val asyncMethod = getMethod("run1Async", String::class.java) + val reserveMethod = getMethod("run1Reserve", String::class.java) + + assertEquals(String::class.java, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + } + + @Test + fun `interface suspend trans property test`() { + with(STPTrans1::class.memberProperties) { + assertTrue(any { it.name == "run1" && it.returnType.classifier == Int::class }) + assertTrue(any { it.name == "run2" && it.returnType.classifier == String::class }) + } + + // run1 + with(STPTrans1::class.java) { + val blockingPropertyMethod = getMethod("getRun1") + val asyncPropertyMethod = getMethod("getRun1Async") + val reservePropertyMethod = getMethod("getRun1Reserve") + + assertEquals(Int::class.javaPrimitiveType, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + // run2 + with(STPTrans1::class.java) { + val blockingPropertyMethod = getMethod("getRun2") + val asyncPropertyMethod = getMethod("getRun2Async") + val reservePropertyMethod = getMethod("getRun2Reserve") + + assertEquals(String::class.java, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + } + + @Test + fun `interface suspend trans function with suffix test`() { + with(STTrans2::class.java) { + val blockingMethod = getMethod("run1Bk") + val asyncMethod = getMethod("run1Ay") + val reserveMethod = getMethod("run1Rs") + + assertEquals(Void.TYPE, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + + with(STTrans2::class.java) { + val blockingMethod = getMethod("run1Bk", String::class.java) + val asyncMethod = getMethod("run1Ay", String::class.java) + val reserveMethod = getMethod("run1Rs", String::class.java) + + assertEquals(String::class.java, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + } + + @Test + fun `interface suspend trans property with suffix test`() { + with(STPTrans2::class.memberProperties) { + assertTrue(any { it.name == "run1Bk" && it.returnType.classifier == Int::class }) + assertTrue(any { it.name == "run2Bk" && it.returnType.classifier == String::class }) + } + + // run1 + with(STPTrans2::class.java) { + val blockingPropertyMethod = getMethod("getRun1Bk") + val asyncPropertyMethod = getMethod("getRun1Ay") + val reservePropertyMethod = getMethod("getRun1Rs") + + assertEquals(Int::class.javaPrimitiveType, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + // run2 + with(STPTrans2::class.java) { + val blockingPropertyMethod = getMethod("getRun2Bk") + val asyncPropertyMethod = getMethod("getRun2Ay") + val reservePropertyMethod = getMethod("getRun2Rs") + + assertEquals(String::class.java, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + } + + @Test + fun `interface suspend trans function with baseName and suffix test`() { + with(STTrans3::class.java) { + val blockingMethod = getMethod("apply1Bk") + val asyncMethod = getMethod("apply1Ay") + val reserveMethod = getMethod("apply1Rs") + + assertEquals(Void.TYPE, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + + with(STTrans3::class.java) { + + val blockingMethod = getMethod("apply1Bk", String::class.java) + val asyncMethod = getMethod("apply1Ay", String::class.java) + val reserveMethod = getMethod("apply1Rs", String::class.java) + + assertEquals(String::class.java, blockingMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncMethod.returnType) + assertEquals(SuspendReserve::class.java, reserveMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncMethod.modifiers)) + assertFalse(Modifier.isAbstract(reserveMethod.modifiers)) + } + } + + @Test + fun `interface suspend trans property with baseName and suffix test`() { + with(STPTrans3::class.memberProperties) { + assertTrue(any { it.name == "apply1Bk" && it.returnType.classifier == Int::class }) + assertTrue(any { it.name == "apply2Bk" && it.returnType.classifier == String::class }) + } + + // run1 + with(STPTrans3::class.java) { + val blockingPropertyMethod = getMethod("getApply1Bk") + val asyncPropertyMethod = getMethod("getApply1Ay") + val reservePropertyMethod = getMethod("getApply1Rs") + + assertEquals(Int::class.javaPrimitiveType, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + // run2 + with(STPTrans3::class.java) { + val blockingPropertyMethod = getMethod("getApply2Bk") + val asyncPropertyMethod = getMethod("getApply2Ay") + val reservePropertyMethod = getMethod("getApply2Rs") + + assertEquals(String::class.java, blockingPropertyMethod.returnType) + assertEquals(CompletableFuture::class.java, asyncPropertyMethod.returnType) + assertEquals(SuspendReserve::class.java, reservePropertyMethod.returnType) + + assertFalse(Modifier.isAbstract(blockingPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(asyncPropertyMethod.modifiers)) + assertFalse(Modifier.isAbstract(reservePropertyMethod.modifiers)) + } + + } + + @Test + fun `typed interface test`() { + with(ITypedTrans1::class) { + assertTrue(memberProperties.any { + it.name == "value" && with(it.returnType.classifier) { + this is KTypeParameter && this.upperBounds.any { b -> b.classifier == Foo::class } + } + }) + assertTrue(memberProperties.any { + it.name == "valueAsync" && it.returnType.classifier == CompletableFuture::class + }) + assertTrue(memberProperties.any { + it.name == "valueReserve" && it.returnType.classifier == SuspendReserve::class + }) + } + with(TypedTrans1Impl::class) { + assertTrue(memberProperties.any { + it.name == "value" && with(it.returnType.classifier) { + this is KTypeParameter && this.upperBounds.any { b -> b.classifier == Bar::class } + } + }) + assertTrue(memberProperties.any { + it.name == "valueAsync" && it.returnType.classifier == CompletableFuture::class + }) + assertTrue(memberProperties.any { + it.name == "valueReserve" && it.returnType.classifier == SuspendReserve::class + }) + } + } + +} diff --git a/simbot-commons/build.gradle.kts b/simbot-commons/build.gradle.kts new file mode 100644 index 000000000..36f66408b --- /dev/null +++ b/simbot-commons/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * Project https://github.com/simple-robot/simpler-robot + * Email ForteScarlet@163.com + * + * This file is part of the Simple Robot Library. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + * + */ + + +subprojects { + +} diff --git a/simbot-gradles/simbot-gradle-suspendtransforms/build.gradle.kts b/simbot-gradles/simbot-gradle-suspendtransforms/build.gradle.kts index 5c126e6dd..b95258423 100644 --- a/simbot-gradles/simbot-gradle-suspendtransforms/build.gradle.kts +++ b/simbot-gradles/simbot-gradle-suspendtransforms/build.gradle.kts @@ -40,8 +40,6 @@ kotlin { configJavaToolchain(JVMConstants.KT_JVM_TARGET_VALUE) } -val suspendTransformVersion = "0.6.0-beta3" - dependencies { - api("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:$suspendTransformVersion") + api(libs.suspend.transform.gradle) } diff --git a/website b/website index 773d65f4d..9e48b7517 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit 773d65f4d358753c2e1029056003329ea704ba93 +Subproject commit 9e48b75171f728f6bb295a4495e50f767fe35421