diff --git a/.github/workflows/publish-v4-release.yml b/.github/workflows/publish-v4-release.yml index 722450991..4b01edce2 100644 --- a/.github/workflows/publish-v4-release.yml +++ b/.github/workflows/publish-v4-release.yml @@ -8,6 +8,7 @@ env: JAVA_VERSION: 21 JAVA_DISTRIBUTION: zulu GRADLE_VERSION: 8.5 + NODE_VERSION: 22 IS_CI: true GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }} @@ -30,6 +31,10 @@ jobs: distribution: ${{ env.JAVA_DISTRIBUTION }} java-version: ${{ env.JAVA_VERSION }} cache: 'gradle' + + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} - name: Run All Tests pre release uses: gradle/actions/setup-gradle@v3 with: @@ -56,7 +61,9 @@ jobs: distribution: ${{ env.JAVA_DISTRIBUTION }} java-version: ${{ env.JAVA_VERSION }} cache: 'gradle' - + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} # setup Gradle - name: Gradle Publish Release uses: gradle/actions/setup-gradle@v3 diff --git a/.github/workflows/publish-v4-snapshot.yml b/.github/workflows/publish-v4-snapshot.yml index bff082316..f7bab78b2 100644 --- a/.github/workflows/publish-v4-snapshot.yml +++ b/.github/workflows/publish-v4-snapshot.yml @@ -21,6 +21,7 @@ env: JAVA_VERSION: 21 JAVA_DISTRIBUTION: zulu GRADLE_VERSION: 8.5 + NODE_VERSION: 22 IS_CI: true GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }} @@ -49,7 +50,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: ${{ env.NODE_VERSION }} - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 @@ -79,10 +80,9 @@ jobs: java-version: ${{ env.JAVA_VERSION }} cache: 'gradle' - # setup Node - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: ${{ env.NODE_VERSION }} - name: Publish snapshots uses: gradle/actions/setup-gradle@v3 diff --git a/.github/workflows/test-v4-branch.yml b/.github/workflows/test-v4-branch.yml index 48cad7218..674fa88d1 100644 --- a/.github/workflows/test-v4-branch.yml +++ b/.github/workflows/test-v4-branch.yml @@ -9,6 +9,7 @@ env: JAVA_VERSION: 21 JAVA_DISTRIBUTION: zulu GRADLE_VERSION: 8.5 + NODE_VERSION: 22 IS_CI: true GRADLE_OPTS: "-Dfile.encoding=UTF-8" @@ -30,6 +31,9 @@ jobs: distribution: ${{ env.JAVA_DISTRIBUTION }} java-version: ${{ env.JAVA_VERSION }} cache: 'gradle' + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} - name: Run V4 All Tests uses: gradle/gradle-build-action@v3 diff --git a/build.gradle.kts b/build.gradle.kts index 7efa91abc..6714094d7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -171,4 +171,13 @@ idea { } } - +// https://kotlinlang.org/docs/js-project-setup.html#node-js +rootProject.plugins.withType { + rootProject.the().apply { + // CI 中配置环境,不再单独下载 + if (isCi) { + download = false + } + } + // "true" for default behavior +} diff --git a/buildSrc/src/main/kotlin/JsConfig.kt b/buildSrc/src/main/kotlin/JsConfig.kt index 5f1708167..7f1ada2fc 100644 --- a/buildSrc/src/main/kotlin/JsConfig.kt +++ b/buildSrc/src/main/kotlin/JsConfig.kt @@ -22,11 +22,8 @@ */ import org.gradle.api.Project -import org.gradle.kotlin.dsl.the -import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmJsTargetDsl -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension inline fun KotlinJsTargetDsl.configJs( @@ -77,7 +74,8 @@ inline fun KotlinWasmJsTargetDsl.configWasmJs( block: () -> Unit = {} ) { if (nodeJs) { - nodejs() + nodejs { + } } // if (nodeJs && isLinux) { // // win in candy node `21.0.0-v8-canary202309143a48826a08` is not supported @@ -100,18 +98,18 @@ inline fun KotlinWasmJsTargetDsl.configWasmJs( } inline fun Project.configWasmJsTest(block: () -> Unit = {}) { - if (false) { - // see https://youtrack.jetbrains.com/issue/KT-63014/Running-tests-with-wasmJs-in-1.9.20-requires-Chrome-Canary#focus=Comments-27-8321383.0-0 - rootProject.the().apply { - // nodeVersion = "21.0.0-v8-canary202309143a48826a08" - version = "21.0.0-v8-canary202309143a48826a08" - downloadBaseUrl = "https://nodejs.org/download/v8-canary" - } - - tasks.withType().configureEach { - args.add("--ignore-engines") - } - } + // if (false) { + // // see https://youtrack.jetbrains.com/issue/KT-63014/Running-tests-with-wasmJs-in-1.9.20-requires-Chrome-Canary#focus=Comments-27-8321383.0-0 + // rootProject.the().apply { + // // nodeVersion = "21.0.0-v8-canary202309143a48826a08" + // version = "21.0.0-v8-canary202309143a48826a08" + // downloadBaseUrl = "https://nodejs.org/download/v8-canary" + // } + // + // tasks.withType().configureEach { + // args.add("--ignore-engines") + // } + // } block() } diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt index 8a3ed66b4..72f4abfae 100644 --- a/buildSrc/src/main/kotlin/P.kt +++ b/buildSrc/src/main/kotlin/P.kt @@ -52,8 +52,8 @@ sealed class P(override val group: String) : ProjectDetail() { */ companion object { - const val VERSION = "4.3.1" - const val NEXT_VERSION = "4.3.2" + const val VERSION = "4.4.0" + const val NEXT_VERSION = "4.4.0" const val SNAPSHOT_VERSION = "$VERSION-SNAPSHOT" const val NEXT_SNAPSHOT_VERSION = "$NEXT_VERSION-SNAPSHOT" diff --git a/settings.gradle.kts b/settings.gradle.kts index b477597c2..6c8a7b578 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -44,6 +44,7 @@ include(":simbot-gradles:simbot-gradle-suspendtransforms") include(":simbot-commons:simbot-common-annotations") include(":simbot-commons:simbot-common-collection") +include(":simbot-commons:simbot-common-streamable") include(":simbot-commons:simbot-common-atomic") include(":simbot-commons:simbot-common-apidefinition") include(":simbot-commons:simbot-common-core") diff --git a/simbot-api/api/simbot-api.api b/simbot-api/api/simbot-api.api index 3aa4041a5..6e96acfb2 100644 --- a/simbot-api/api/simbot-api.api +++ b/simbot-api/api/simbot-api.api @@ -371,6 +371,8 @@ public abstract interface class love/forte/simbot/bot/BotManager : love/forte/si public fun all (Llove/forte/simbot/common/id/ID;)Lkotlin/sequences/Sequence; public fun allToList ()Ljava/util/List; public fun allToList (Llove/forte/simbot/common/id/ID;)Ljava/util/List; + public fun allToStreamable ()Llove/forte/simbot/common/streamable/Streamable; + public fun allToStreamable (Llove/forte/simbot/common/id/ID;)Llove/forte/simbot/common/streamable/Streamable; public fun asFuture ()Ljava/util/concurrent/CompletableFuture; public abstract fun cancel (Ljava/lang/Throwable;)V public static synthetic fun cancel$default (Llove/forte/simbot/bot/BotManager;Ljava/lang/Throwable;ILjava/lang/Object;)V @@ -393,6 +395,7 @@ public final class love/forte/simbot/bot/BotManagerUtil { public abstract interface class love/forte/simbot/bot/BotManagers : java/util/Collection, kotlin/jvm/internal/markers/KMappedMarker { public fun allBots ()Lkotlin/sequences/Sequence; + public fun allBotsToStreamable ()Llove/forte/simbot/common/streamable/Streamable; public fun firstBot ()Llove/forte/simbot/bot/Bot; public fun firstBot (Llove/forte/simbot/common/id/ID;)Llove/forte/simbot/bot/Bot; } @@ -1206,6 +1209,7 @@ public abstract interface class love/forte/simbot/event/EventListener { public abstract interface class love/forte/simbot/event/EventListenerContainer { public abstract fun getListeners ()Lkotlin/sequences/Sequence; + public fun listenersToStreamable ()Llove/forte/simbot/common/streamable/Streamable; } public abstract interface class love/forte/simbot/event/EventListenerContext { diff --git a/simbot-api/build.gradle.kts b/simbot-api/build.gradle.kts index e36010d86..a2dc96266 100644 --- a/simbot-api/build.gradle.kts +++ b/simbot-api/build.gradle.kts @@ -75,6 +75,7 @@ kotlin { implementation(project(":simbot-commons:simbot-common-annotations")) implementation(project(":simbot-logger")) + api(project(":simbot-commons:simbot-common-streamable")) api(project(":simbot-commons:simbot-common-suspend-runner")) api(project(":simbot-commons:simbot-common-core")) api(project(":simbot-commons:simbot-common-collection")) diff --git a/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManager.kt b/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManager.kt index 897d7a44e..e8fd8a43c 100644 --- a/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManager.kt +++ b/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManager.kt @@ -27,6 +27,8 @@ import love.forte.simbot.ability.CompletionAware import love.forte.simbot.ability.LifecycleAware import love.forte.simbot.common.function.MergeableFactory import love.forte.simbot.common.id.ID +import love.forte.simbot.common.streamable.Streamable +import love.forte.simbot.common.streamable.Streamable.Companion.asStreamable import love.forte.simbot.plugin.PluginFactory import love.forte.simbot.suspendrunner.ST @@ -57,6 +59,24 @@ public interface BotManager : AutoConfigurableBotPlugin, LifecycleAware, Complet */ public fun all(id: ID): Sequence = all().filter { bot -> bot.id == id } + /** + * 得到所有的 [Bot] 并转化为 [Streamable]。 + * + * @since 4.4.0 + * @see all + */ + public fun allToStreamable(): Streamable = + all().asStreamable() + + /** + * 得到所有 `id` 符合条件的 [Bot] 并转化为 [Streamable]。 + * + * @since 4.4.0 + * @see all + */ + public fun allToStreamable(id: ID): Streamable = + all(id).asStreamable() + /** * 将 [all] 收集为 [List] 并返回。 * diff --git a/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManagers.kt b/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManagers.kt index 7d35ca8fd..95a79c7f3 100644 --- a/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManagers.kt +++ b/simbot-api/src/commonMain/kotlin/love/forte/simbot/bot/BotManagers.kt @@ -28,6 +28,8 @@ package love.forte.simbot.bot import love.forte.simbot.common.collection.toImmutable import love.forte.simbot.common.id.ID +import love.forte.simbot.common.streamable.Streamable +import love.forte.simbot.common.streamable.Streamable.Companion.asStreamable import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -41,6 +43,13 @@ public interface BotManagers : Collection { */ public fun allBots(): Sequence = asSequence().flatMap { it.all() } + /** + * 获取 [allBots] 的流转化器。 + * + * @since 4.4.0 + */ + public fun allBotsToStreamable(): Streamable = allBots().asStreamable() + /** * 尝试获取第一个 [BotManager] 中的第一个 [Bot]。 * diff --git a/simbot-api/src/commonMain/kotlin/love/forte/simbot/event/EventListenerContainer.kt b/simbot-api/src/commonMain/kotlin/love/forte/simbot/event/EventListenerContainer.kt index 7fde2e958..06c2d2be7 100644 --- a/simbot-api/src/commonMain/kotlin/love/forte/simbot/event/EventListenerContainer.kt +++ b/simbot-api/src/commonMain/kotlin/love/forte/simbot/event/EventListenerContainer.kt @@ -4,7 +4,7 @@ * Project https://github.com/simple-robot/simpler-robot * Email ForteScarlet@163.com * - * This file is part of the Simple Robot Library. + * This file is part of the Simple Robot Library (Alias: simple-robot, simbot, etc.). * * 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 @@ -23,6 +23,9 @@ package love.forte.simbot.event +import love.forte.simbot.common.streamable.Streamable +import love.forte.simbot.common.streamable.Streamable.Companion.asStreamable + /** * 事件监听器的“容器”接口,提供用于获取其中的所有 [EventListener] 的API。 @@ -37,5 +40,11 @@ public interface EventListenerContainer { */ public val listeners: Sequence - + /** + * 获取到 [listeners] 并转化为 [Streamable] + * + * @see listeners + */ + public fun listenersToStreamable(): Streamable = + listeners.asStreamable() } diff --git a/simbot-api/src/jvmMain/java/module-info.java b/simbot-api/src/jvmMain/java/module-info.java index 1a759763f..29bbcdca9 100644 --- a/simbot-api/src/jvmMain/java/module-info.java +++ b/simbot-api/src/jvmMain/java/module-info.java @@ -31,6 +31,7 @@ requires simbot.logger; requires static org.jetbrains.annotations; requires static simbot.common.annotations; + requires simbot.common.streamable; requires simbot.common.suspendrunner; requires simbot.common.core; requires simbot.common.collection; diff --git a/simbot-commons/simbot-common-streamable/api/simbot-common-streamable.api b/simbot-commons/simbot-common-streamable/api/simbot-common-streamable.api new file mode 100644 index 000000000..eb86e45ae --- /dev/null +++ b/simbot-commons/simbot-common-streamable/api/simbot-common-streamable.api @@ -0,0 +1,15 @@ +public final class love/forte/simbot/common/streamable/Streamable : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { + public static final field Companion Llove/forte/simbot/common/streamable/Streamable$Companion; + public synthetic fun (Lkotlin/sequences/Sequence;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun asSequence ()Lkotlin/sequences/Sequence; + public final fun asStream ()Ljava/util/stream/Stream; + public final fun collectTo (Ljava/util/Collection;)Ljava/util/Collection; + public final fun collectToList ()Ljava/util/List; + public fun iterator ()Ljava/util/Iterator; + public static final fun of (Lkotlin/sequences/Sequence;)Llove/forte/simbot/common/streamable/Streamable; +} + +public final class love/forte/simbot/common/streamable/Streamable$Companion { + public final fun of (Lkotlin/sequences/Sequence;)Llove/forte/simbot/common/streamable/Streamable; +} + diff --git a/simbot-commons/simbot-common-streamable/build.gradle.kts b/simbot-commons/simbot-common-streamable/build.gradle.kts new file mode 100644 index 000000000..fd4ff6100 --- /dev/null +++ b/simbot-commons/simbot-common-streamable/build.gradle.kts @@ -0,0 +1,92 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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.gradle.common.kotlin.multiplatform.applyTier1 +import love.forte.gradle.common.kotlin.multiplatform.applyTier2 +import love.forte.gradle.common.kotlin.multiplatform.applyTier3 +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl + +plugins { + kotlin("multiplatform") + kotlin("plugin.serialization") + id("simbot.dokka-module-configuration") +} + +configJavaCompileWithModule("simbot.common.streamable") +apply(plugin = "simbot-multiplatform-maven-publish") + +kotlin { + explicitApi() + applyDefaultHierarchyTemplate() + + configKotlinJvm(JVMConstants.KT_JVM_TARGET_VALUE) + + js(IR) { + configJs() + } + + applyTier1() + applyTier2() + applyTier3() + + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + configWasmJs() + } + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + freeCompilerArgs.addAll( + "-Xexpect-actual-classes" + ) + } + + sourceSets { + commonTest { + dependencies { + implementation(kotlin("test")) + } + } + + jvmTest { + dependencies { + implementation(kotlin("test-junit5")) + } + } + } +} + +configWasmJsTest() + +// https://book.kotlincn.net/text/testing-strategies.html +tasks.withType { + jvmArgs( + "--add-opens", + "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", + "java.base/jdk.internal.util=ALL-UNNAMED", + "--add-exports", + "java.base/sun.security.action=ALL-UNNAMED" + ) +} diff --git a/simbot-commons/simbot-common-streamable/src/commonMain/kotlin/love/forte/simbot/common/streamable/Streamable.kt b/simbot-commons/simbot-common-streamable/src/commonMain/kotlin/love/forte/simbot/common/streamable/Streamable.kt new file mode 100644 index 000000000..b1bd84c7b --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/commonMain/kotlin/love/forte/simbot/common/streamable/Streamable.kt @@ -0,0 +1,66 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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 . + * + */ + +package love.forte.simbot.common.streamable + + +/** + * + * 一个可流化的包装器类型。 + * 用于提供更便捷地对 [Sequence] 进行转化的API。 + * + * [Streamable] 是一种用于便捷操作的**转化器**, + * 而不是直接对流进行操作的类型。 + * 它的作用是减小不同平台间对 [Sequence] 的部分操作差异。 + * + * [Streamable] 会有部分平台专供的API,例如在 JVM 中可转化为 `Stream`。 + * + * @since 4.4.0 + * + * @author ForteScarlet + */ +public expect class Streamable private constructor(seq: Sequence) : Iterable { + /** + * 转化为 [Sequence]. + */ + public fun asSequence(): Sequence + + override fun iterator(): Iterator + + /** + * 将结果转化为 [List] + */ + public fun collectToList(): List + + /** + * 将内部的序列结果收集到 [C] 中。 + */ + public fun > collectTo(collection: C): C + + public companion object { + /** + * 将 [Sequence] 转化为 [Streamable] + */ + public fun Sequence.asStreamable(): Streamable + } +} diff --git a/simbot-commons/simbot-common-streamable/src/jsMain/kotlin/love/forte/simbot/common/streamable/Streamable.js.kt b/simbot-commons/simbot-common-streamable/src/jsMain/kotlin/love/forte/simbot/common/streamable/Streamable.js.kt new file mode 100644 index 000000000..48c0d8fa5 --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/jsMain/kotlin/love/forte/simbot/common/streamable/Streamable.js.kt @@ -0,0 +1,71 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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 . + * + */ + +package love.forte.simbot.common.streamable + +/** + * + * 一个可流化的包装器类型。 + * 用于提供更便捷地对 [Sequence] 进行转化的API。 + * + * [Streamable] 是一种用于便捷操作的**转化器**, + * 而不是直接对流进行操作的类型。 + * 它的作用是尽可能减小不同平台间对 [Sequence] 的操作差异。 + * + * [Streamable] 会有部分平台专供的API,例如在 JVM 中可转化为 `Stream`。 + * + * @since 4.4.0 + * + * @author ForteScarlet + */ +public actual class Streamable private actual constructor( + private val seq: Sequence +) : Iterable { + public actual fun asSequence(): Sequence = seq + actual override fun iterator(): Iterator = seq.iterator() + + /** + * 将结果转化为 [List] + */ + public actual fun collectToList(): List = seq.toList() + + /** + * 将内部的序列结果收集到 [C] 中。 + */ + public actual fun > collectTo(collection: C): C = + seq.toCollection(collection) + + /** + * 收集元素为数组。 + */ + public fun collectToArray(): Array = + seq.toList().toTypedArray() + + public actual companion object { + /** + * 将 [Sequence] 转化为 [Streamable] + */ + public actual fun Sequence.asStreamable(): Streamable = + Streamable(this) + } +} diff --git a/simbot-commons/simbot-common-streamable/src/jvmMain/java/module-info.java b/simbot-commons/simbot-common-streamable/src/jvmMain/java/module-info.java new file mode 100644 index 000000000..12032c88f --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/jvmMain/java/module-info.java @@ -0,0 +1,5 @@ +module simbot.common.streamable { + requires kotlin.stdlib; + + exports love.forte.simbot.common.streamable; +} diff --git a/simbot-commons/simbot-common-streamable/src/jvmMain/kotlin/love/forte/simbot/common/streamable/Streamable.jvm.kt b/simbot-commons/simbot-common-streamable/src/jvmMain/kotlin/love/forte/simbot/common/streamable/Streamable.jvm.kt new file mode 100644 index 000000000..3d9f49e98 --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/jvmMain/kotlin/love/forte/simbot/common/streamable/Streamable.jvm.kt @@ -0,0 +1,77 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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 . + * + */ + +package love.forte.simbot.common.streamable + +import java.util.stream.Stream +import kotlin.streams.asStream + +/** + * + * 一个可流化的包装器类型。 + * 用于提供更便捷地对 [Sequence] 进行转化的API。 + * + * [Streamable] 是一种用于便捷操作的**转化器**, + * 而不是直接对流进行操作的类型。 + * 它的作用是尽可能减小不同平台间对 [Sequence] 的操作差异。 + * + * [Streamable] 会有部分平台专供的API,例如在 JVM 中可转化为 [Stream]。 + * + * @since 4.4.0 + * + * @author ForteScarlet + */ +public actual class Streamable private actual constructor( + private val seq: Sequence +) : Iterable { + public actual fun asSequence(): Sequence = seq + actual override fun iterator(): Iterator = seq.iterator() + + /** + * 将结果转化为 [List] + */ + public actual fun collectToList(): List = seq.toList() + + /** + * 将内部的序列结果收集到 [C] 中。 + */ + public actual fun > collectTo(collection: C): C = + seq.toCollection(collection) + + // ↓ 为了这碟醋包了这盘饺子 + + /** + * 转化为 [Stream]. + */ + public fun asStream(): Stream = seq.asStream() + + public actual companion object { + /** + * 将 [Sequence] 转化为 [Streamable] + */ + @JvmName("of") + @JvmStatic + public actual fun Sequence.asStreamable(): Streamable = + Streamable(this) + } +} diff --git a/simbot-commons/simbot-common-streamable/src/nativeMain/kotlin/love/forte/simbot/common/streamable/Streamable.native.kt b/simbot-commons/simbot-common-streamable/src/nativeMain/kotlin/love/forte/simbot/common/streamable/Streamable.native.kt new file mode 100644 index 000000000..33a2dc65f --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/nativeMain/kotlin/love/forte/simbot/common/streamable/Streamable.native.kt @@ -0,0 +1,66 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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 . + * + */ + +package love.forte.simbot.common.streamable + + +/** + * + * 一个可流化的包装器类型。 + * 用于提供更便捷地对 [Sequence] 进行转化的API。 + * + * [Streamable] 是一种用于便捷操作的**转化器**, + * 而不是直接对流进行操作的类型。 + * 它的作用是尽可能减小不同平台间对 [Sequence] 的操作差异。 + * + * [Streamable] 会有部分平台专供的API,例如在 JVM 中可转化为 `Stream`。 + * + * @since 4.4.0 + * + * @author ForteScarlet + */ +public actual class Streamable private actual constructor( + private val seq: Sequence +) : Iterable { + public actual fun asSequence(): Sequence = seq + actual override fun iterator(): Iterator = seq.iterator() + + /** + * 将结果转化为 [List] + */ + public actual fun collectToList(): List = seq.toList() + + /** + * 将内部的序列结果收集到 [C] 中。 + */ + public actual fun > collectTo(collection: C): C = + seq.toCollection(collection) + + public actual companion object { + /** + * 将 [Sequence] 转化为 [Streamable] + */ + public actual fun Sequence.asStreamable(): Streamable = + Streamable(this) + } +} diff --git a/simbot-commons/simbot-common-streamable/src/wasmJsMain/kotlin/love/forte/simbot/common/streamable/Streamable.wasmJs.kt b/simbot-commons/simbot-common-streamable/src/wasmJsMain/kotlin/love/forte/simbot/common/streamable/Streamable.wasmJs.kt new file mode 100644 index 000000000..48c0d8fa5 --- /dev/null +++ b/simbot-commons/simbot-common-streamable/src/wasmJsMain/kotlin/love/forte/simbot/common/streamable/Streamable.wasmJs.kt @@ -0,0 +1,71 @@ +/* + * 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 (Alias: simple-robot, simbot, etc.). + * + * 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 . + * + */ + +package love.forte.simbot.common.streamable + +/** + * + * 一个可流化的包装器类型。 + * 用于提供更便捷地对 [Sequence] 进行转化的API。 + * + * [Streamable] 是一种用于便捷操作的**转化器**, + * 而不是直接对流进行操作的类型。 + * 它的作用是尽可能减小不同平台间对 [Sequence] 的操作差异。 + * + * [Streamable] 会有部分平台专供的API,例如在 JVM 中可转化为 `Stream`。 + * + * @since 4.4.0 + * + * @author ForteScarlet + */ +public actual class Streamable private actual constructor( + private val seq: Sequence +) : Iterable { + public actual fun asSequence(): Sequence = seq + actual override fun iterator(): Iterator = seq.iterator() + + /** + * 将结果转化为 [List] + */ + public actual fun collectToList(): List = seq.toList() + + /** + * 将内部的序列结果收集到 [C] 中。 + */ + public actual fun > collectTo(collection: C): C = + seq.toCollection(collection) + + /** + * 收集元素为数组。 + */ + public fun collectToArray(): Array = + seq.toList().toTypedArray() + + public actual companion object { + /** + * 将 [Sequence] 转化为 [Streamable] + */ + public actual fun Sequence.asStreamable(): Streamable = + Streamable(this) + } +} diff --git a/website b/website index ddfbdb4dd..78257d2e8 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit ddfbdb4dd9d46a9c49ebe3e8f8b4537bc836bbc4 +Subproject commit 78257d2e8f8c686328c1ef7dc72bae2e559b02a1