diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt index 152ac798b..8857cb0c1 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt @@ -12,6 +12,25 @@ package net.mamoe.mirai.console.codegen import org.intellij.lang.annotations.Language +import kotlin.reflect.KClass +import kotlin.reflect.full.functions +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.full.isSubclassOf + +inline fun runCodegenInObject() = runCodegenInObject(T::class) + +fun runCodegenInObject(clazz: KClass<*>) { + clazz.nestedClasses + .filter { it.isSubclassOf(RegionCodegen::class) } + .associateWith { kClass -> kClass.functions.find { it.name == "main" && it.hasAnnotation() } } + .filter { it.value != null } + .forEach { (kClass, entryPoint) -> + println("---------------------------------------------") + println("Running Codegen: ${kClass.simpleName}") + entryPoint!!.call(kClass.objectInstance, arrayOf()) + println("---------------------------------------------") + } +} abstract class Replacer(private val name: String) : (String) -> String { override fun toString(): String { diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/MessageScopeCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/MessageScopeCodegen.kt new file mode 100644 index 000000000..0f5dd7839 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/MessageScopeCodegen.kt @@ -0,0 +1,198 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.console.codegen + +internal val TypeCandidatesForMessageScope = arrayOf( + KtType("Contact"), + KtType("CommandSender"), +) + +internal val KtMessageScope = KtType("MessageScope") + +internal fun Array.arrangements(): List> { + val result = mutableListOf>() + for (a in this) { + for (b in this) { + result.add(a to b) + } + } + return result +} + +internal fun Array.distinctArrangements(): List> { + return this.arrangements().distinctBy { it.first.toString().hashCode() + it.second.toString().hashCode() } +} + +internal object MessageScopeCodegen { + object IterableMessageScopeBuildersCodegen : RegionCodegen("MessageScope.kt"), DefaultInvoke { + @JvmStatic + fun main(args: Array) = super.startIndependently() + override val defaultInvokeArgs: List = listOf(KtString) // invoke once + + @Suppress( + "RedundantVisibilityModifier", "ClassName", "KDocUnresolvedReference", "RedundantSuspendModifier", + "SpellCheckingInspection" + ) + override fun StringBuilder.apply(ktType: KtType) { + for (collectionName in arrayOf("Iterable", "Sequence", "Array")) { + for (candidate in (TypeCandidatesForMessageScope + KtMessageScope)) { + appendKCode( + """ + @JvmName("toMessageScope${candidate.standardName.capitalize()}${collectionName.capitalize()}") + public fun $collectionName<$candidate?>.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> CombinedScope(acc, messageScope.asMessageScopeOrNoop()) } + } + """ + ) + appendLine() + } + } + for (candidate in (TypeCandidatesForMessageScope + KtMessageScope)) { + appendKCode( + """ + @JvmSynthetic + @JvmName("toMessageScope${candidate.standardName.capitalize()}Flow") + public suspend fun Flow<$candidate>.toMessageScope(): MessageScope { // Flow.firstOrNull isn't yet supported + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> CombinedScope(acc, messageScope.asMessageScope()) } + } + """ + ) + appendLine() + } + } + } + + object MessageScopeBuildersCodegen : RegionCodegen("MessageScope.kt"), DefaultInvoke { + @JvmStatic + fun main(args: Array) = super.startIndependently() + override val defaultInvokeArgs: List = listOf(KtString) // invoke once + + @Suppress("RedundantVisibilityModifier", "ClassName", "KDocUnresolvedReference") + override fun StringBuilder.apply(ktType: KtType) { + for (candidate in TypeCandidatesForMessageScope) { + appendKCode( + """ + public fun ${candidate}.asMessageScope(): MessageScope = createScopeDelegate(this) + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) { + appendKCode( + """ + @LowPriorityInOverloadResolution + public fun ${a}.scopeWith(vararg others: ${b}): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } + } + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) { + appendKCode( + """ + @LowPriorityInOverloadResolution + public fun ${a}?.scopeWithNotNull(vararg others: ${b}?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } + } + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).distinctArrangements()) { + appendKCode( + """ + public fun ${a}.scopeWith(other: ${b}): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) + } + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).distinctArrangements()) { + appendKCode( + """ + public fun ${a}?.scopeWithNotNull(other: ${b}?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } + } + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) { + appendKCode( + """ + public inline fun ${a}.scopeWith(vararg others: ${b}, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) + } + """ + ) + appendLine() + } + + for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) { + appendKCode( + """ + public inline fun ${a}?.scopeWithNotNull(vararg others: ${b}?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) + } + """ + ) + appendLine() + } + + for (a in (TypeCandidatesForMessageScope + KtMessageScope)) { + appendKCode( + """ + @Deprecated("Senseless scopeWith. Use asMessageScope.", ReplaceWith("this.asMessageScope()", "net.mamoe.mirai.console.util.asMessageScope")) + public inline fun ${a}.scopeWith(): MessageScope = asMessageScope() + """ + ) + appendLine() + } + + for (a in (TypeCandidatesForMessageScope + KtMessageScope)) { + appendKCode( + """ + @Deprecated( + "Senseless scopeWith. Use .asMessageScope().invoke.", + ReplaceWith("this.asMessageScope()(action)", "net.mamoe.mirai.console.util.asMessageScope", "net.mamoe.mirai.console.util.invoke") + ) + public inline fun ${a}.scopeWith(action: MessageScope.() -> R): R = asMessageScope()(action) +""" + ) + appendLine() + } + + } + } + + + /** + * 运行本 object 中所有嵌套 object Codegen + */ + @OptIn(ExperimentalStdlibApi::class) + @JvmStatic + fun main(args: Array) { + runCodegenInObject(this::class) + } +} \ No newline at end of file diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index 57852db47..0066d071b 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate", "unused","PRE_RELEASE_CLASS") +@file:Suppress("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate", "unused", "PRE_RELEASE_CLASS") package net.mamoe.mirai.console.codegen @@ -71,6 +71,16 @@ sealed class KtType { object KtMap : KtType() { override val standardName: String get() = "Map" } + + data class Custom(override val standardName: String) : KtType() { + override fun toString(): String { + return standardName + } + } + + companion object { + operator fun invoke(standardName: String): KtType = Custom(standardName) + } } val KtPrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt index 1521889da..aa734e47f 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt @@ -165,6 +165,7 @@ public interface CommandSender : CoroutineScope { * * 对于 [MemberCommandSender], 这个函数总是发送给所在群 */ + @JvmDefault @JvmBlockingBridge public suspend fun sendMessage(message: String): MessageReceipt? @@ -259,9 +260,7 @@ public sealed class AbstractCommandSender : CommandSender, CoroutineScope { public abstract override val bot: Bot? public abstract override val subject: Contact? public abstract override val user: User? - public abstract override suspend fun sendMessage(message: Message): MessageReceipt? public abstract override fun toString(): String - public override suspend fun sendMessage(message: String): MessageReceipt? = sendMessage(PlainText(message)) @ConsoleExperimentalAPI("This is unstable and might get changed") override suspend fun catchExecutionException(e: Throwable) { @@ -502,6 +501,11 @@ public abstract class ConsoleCommandSender @ConsoleFrontEndImplementation constr MiraiConsoleImplementationBridge.consoleCommandSender.sendMessage(message) return null } + + override suspend fun sendMessage(message: String): MessageReceipt? { + MiraiConsoleImplementationBridge.consoleCommandSender.sendMessage(message) + return null + } } } @@ -567,7 +571,11 @@ public interface UserCommandSender : CommandSender { public sealed class AbstractUserCommandSender : UserCommandSender, AbstractCommandSender() { public override val bot: Bot get() = user.bot // don't final public final override val name: String get() = user.nameCardOrNick + + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) + + @JvmBlockingBridge public override suspend fun sendMessage(message: Message): MessageReceipt = user.sendMessage(message) } @@ -580,7 +588,11 @@ public open class FriendCommandSender internal constructor( ) : AbstractUserCommandSender(), CoroutineScope by user.childScope("FriendCommandSender") { public override val subject: Contact get() = user public override fun toString(): String = "FriendCommandSender($user)" + + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) + + @JvmBlockingBridge public override suspend fun sendMessage(message: Message): MessageReceipt = user.sendMessage(message) } @@ -596,7 +608,11 @@ public open class MemberCommandSender internal constructor( public override val group: Group get() = user.group public override val subject: Contact get() = group public override fun toString(): String = "MemberCommandSender($user)" + + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) + + @JvmBlockingBridge public override suspend fun sendMessage(message: Message): MessageReceipt = user.sendMessage(message) } @@ -612,7 +628,11 @@ public open class TempCommandSender internal constructor( public override val group: Group get() = user.group public override val subject: Contact get() = group public override fun toString(): String = "TempCommandSender($user)" + + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) + + @JvmBlockingBridge public override suspend fun sendMessage(message: Message): MessageReceipt = user.sendMessage(message) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/MessageScope.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/MessageScope.kt new file mode 100644 index 000000000..57d2fab0c --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/MessageScope.kt @@ -0,0 +1,555 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress( + "NOTHING_TO_INLINE", "INAPPLICABLE_JVM_NAME", "FunctionName", "SuspendFunctionOnCoroutineScope", + "unused", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER" +) + +package net.mamoe.mirai.console.util + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.fold +import net.mamoe.kjbb.JvmBlockingBridge +import net.mamoe.mirai.console.command.CommandSender +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.message.data.Message +import kotlin.internal.InlineOnly +import kotlin.internal.LowPriorityInOverloadResolution + +@ConsoleExperimentalAPI +public interface MessageScope { + /** + * 立刻发送一条消息. + */ + @JvmBlockingBridge + public suspend fun sendMessage(message: Message) + + /** + * 立刻发送一条消息. + */ + @JvmDefault + @JvmBlockingBridge + public suspend fun sendMessage(message: String) +} + +@JvmSynthetic +public inline operator fun MS.invoke(action: MS.() -> R): R = this.action() + +/////////////////////////////////////////////////////////////////////////// +// Builders +/////////////////////////////////////////////////////////////////////////// + +//// region MessageScopeBuilders CODEGEN //// + +public fun Contact.asMessageScope(): MessageScope = createScopeDelegate(this) + +public fun CommandSender.asMessageScope(): MessageScope = createScopeDelegate(this) + +@LowPriorityInOverloadResolution +public fun Contact.scopeWith(vararg others: Contact): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun Contact.scopeWith(vararg others: CommandSender): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun Contact.scopeWith(vararg others: MessageScope): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender.scopeWith(vararg others: Contact): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender.scopeWith(vararg others: CommandSender): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender.scopeWith(vararg others: MessageScope): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope.scopeWith(vararg others: Contact): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope.scopeWith(vararg others: CommandSender): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope.scopeWith(vararg others: MessageScope): MessageScope { + return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun Contact?.scopeWithNotNull(vararg others: Contact?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun Contact?.scopeWithNotNull(vararg others: CommandSender?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun Contact?.scopeWithNotNull(vararg others: MessageScope?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender?.scopeWithNotNull(vararg others: Contact?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender?.scopeWithNotNull(vararg others: CommandSender?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun CommandSender?.scopeWithNotNull(vararg others: MessageScope?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope?.scopeWithNotNull(vararg others: Contact?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope?.scopeWithNotNull(vararg others: CommandSender?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +@LowPriorityInOverloadResolution +public fun MessageScope?.scopeWithNotNull(vararg others: MessageScope?): MessageScope { + return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) } +} + +public fun Contact.scopeWith(other: Contact): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun Contact.scopeWith(other: CommandSender): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun Contact.scopeWith(other: MessageScope): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun CommandSender.scopeWith(other: CommandSender): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun CommandSender.scopeWith(other: MessageScope): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun MessageScope.scopeWith(other: MessageScope): MessageScope { + return CombinedScope(asMessageScope(), other.asMessageScope()) +} + +public fun Contact?.scopeWithNotNull(other: Contact?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public fun Contact?.scopeWithNotNull(other: CommandSender?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public fun Contact?.scopeWithNotNull(other: MessageScope?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public fun CommandSender?.scopeWithNotNull(other: CommandSender?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public fun CommandSender?.scopeWithNotNull(other: MessageScope?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public fun MessageScope?.scopeWithNotNull(other: MessageScope?): MessageScope { + @Suppress("DuplicatedCode") + return when { + this == null && other == null -> NoopMessageScope + this == null && other != null -> other.asMessageScope() + this != null && other == null -> this.asMessageScope() + this != null && other != null -> CombinedScope(asMessageScope(), other.asMessageScope()) + else -> null!! + } +} + +public inline fun Contact.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun Contact.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun Contact.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun CommandSender.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun CommandSender.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun CommandSender.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun MessageScope.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun MessageScope.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun MessageScope.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R { + return scopeWith(*others).invoke(action) +} + +public inline fun Contact?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun Contact?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun Contact?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun CommandSender?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun CommandSender?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun CommandSender?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun MessageScope?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun MessageScope?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +public inline fun MessageScope?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R { + return scopeWithNotNull(*others).invoke(action) +} + +@Deprecated( + "Senseless scopeWith. Use asMessageScope.", + ReplaceWith("this.asMessageScope()", "net.mamoe.mirai.console.util.asMessageScope") +) +public inline fun Contact.scopeWith(): MessageScope = asMessageScope() + +@Deprecated( + "Senseless scopeWith. Use asMessageScope.", + ReplaceWith("this.asMessageScope()", "net.mamoe.mirai.console.util.asMessageScope") +) +public inline fun CommandSender.scopeWith(): MessageScope = asMessageScope() + +@Deprecated( + "Senseless scopeWith. Use asMessageScope.", + ReplaceWith("this.asMessageScope()", "net.mamoe.mirai.console.util.asMessageScope") +) +public inline fun MessageScope.scopeWith(): MessageScope = asMessageScope() + +@Deprecated( + "Senseless scopeWith. Use .asMessageScope().invoke.", + ReplaceWith( + "this.asMessageScope()(action)", + "net.mamoe.mirai.console.util.asMessageScope", + "net.mamoe.mirai.console.util.invoke" + ) +) +public inline fun Contact.scopeWith(action: MessageScope.() -> R): R = asMessageScope()(action) + +@Deprecated( + "Senseless scopeWith. Use .asMessageScope().invoke.", + ReplaceWith( + "this.asMessageScope()(action)", + "net.mamoe.mirai.console.util.asMessageScope", + "net.mamoe.mirai.console.util.invoke" + ) +) +public inline fun CommandSender.scopeWith(action: MessageScope.() -> R): R = asMessageScope()(action) + +@Deprecated( + "Senseless scopeWith. Use .asMessageScope().invoke.", + ReplaceWith( + "this.asMessageScope()(action)", + "net.mamoe.mirai.console.util.asMessageScope", + "net.mamoe.mirai.console.util.invoke" + ) +) +public inline fun MessageScope.scopeWith(action: MessageScope.() -> R): R = asMessageScope()(action) + +//// endregion MessageScopeBuilders CODEGEN //// + +//// region IterableMessageScopeBuilders CODEGEN //// + +@JvmName("toMessageScopeContactIterable") +public fun Iterable.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeCommandSenderIterable") +public fun Iterable.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeMessageScopeIterable") +public fun Iterable.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeContactSequence") +public fun Sequence.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeCommandSenderSequence") +public fun Sequence.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeMessageScopeSequence") +public fun Sequence.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeContactArray") +public fun Array.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeCommandSenderArray") +public fun Array.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmName("toMessageScopeMessageScopeArray") +public fun Array.toMessageScope(): MessageScope { + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScopeOrNoop() + ) + } +} + +@JvmSynthetic +@JvmName("toMessageScopeContactFlow") +public suspend fun Flow.toMessageScope(): MessageScope { // Flow.firstOrNull isn't yet supported + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScope() + ) + } +} + +@JvmSynthetic +@JvmName("toMessageScopeCommandSenderFlow") +public suspend fun Flow.toMessageScope(): MessageScope { // Flow.firstOrNull isn't yet supported + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScope() + ) + } +} + +@JvmSynthetic +@JvmName("toMessageScopeMessageScopeFlow") +public suspend fun Flow.toMessageScope(): MessageScope { // Flow.firstOrNull isn't yet supported + return this.fold(this.firstOrNull().asMessageScopeOrNoop()) { acc, messageScope -> + CombinedScope( + acc, + messageScope.asMessageScope() + ) + } +} + +//// endregion IterableMessageScopeBuilders CODEGEN //// + +/////////////////////////////////////////////////////////////////////////// +// Internals +/////////////////////////////////////////////////////////////////////////// + +// these three are for codegen + +@PublishedApi +@InlineOnly +internal inline fun MessageScope.asMessageScope(): MessageScope = this + +@InlineOnly +private inline fun MessageScope?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope + +@InlineOnly +private inline fun Contact?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope + +@InlineOnly +private inline fun CommandSender?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope + +@InlineOnly +private inline fun createScopeDelegate(o: CommandSender) = CommandSenderAsMessageScope(o) + +@InlineOnly +private inline fun createScopeDelegate(o: Contact) = ContactAsMessageScope(o) + +private class CombinedScope( + private val first: MessageScope, + private val second: MessageScope +) : MessageScope { + override suspend fun sendMessage(message: Message) { + first.sendMessage(message) + second.sendMessage(message) + } + + override suspend fun sendMessage(message: String) { + first.sendMessage(message) + second.sendMessage(message) + } +} + +private class CommandSenderAsMessageScope( + private val sender: CommandSender +) : MessageScope { + override suspend fun sendMessage(message: Message) { + sender.sendMessage(message) + } + + override suspend fun sendMessage(message: String) { + sender.sendMessage(message) + } +} + +private class ContactAsMessageScope( + private val sender: Contact +) : MessageScope { + override suspend fun sendMessage(message: Message) { + sender.sendMessage(message) + } + + override suspend fun sendMessage(message: String) { + sender.sendMessage(message) + } +} + +private object NoopMessageScope : MessageScope { + override suspend fun sendMessage(message: Message) { + } + + override suspend fun sendMessage(message: String) { + } +} \ No newline at end of file