Ver Fonte

Make CombinedMessage internal

Him188 há 6 anos atrás
pai
commit
4184b5f7d9

+ 6 - 19
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt

@@ -14,7 +14,6 @@ package net.mamoe.mirai.message.data
 
 import net.mamoe.mirai.utils.MiraiExperimentalAPI
 import net.mamoe.mirai.utils.MiraiInternalAPI
-import net.mamoe.mirai.utils.PlannedRemoval
 import kotlin.jvm.JvmMultifileClass
 import kotlin.jvm.JvmName
 import kotlin.jvm.JvmSynthetic
@@ -29,8 +28,7 @@ import kotlin.jvm.JvmSynthetic
  *
  * Left-biased list
  */
-@MiraiInternalAPI("this API is going to be internal")
-class CombinedMessage
+internal class CombinedMessage
 internal constructor(
     internal val left: Message, // 必须已经完成 constrain single
     internal val tail: Message
@@ -44,22 +42,11 @@ internal constructor(
         return asSequence().iterator()
     }
 
-    @PlannedRemoval("1.0.0")
-    @Deprecated(
-        "有歧义, 自行使用 contentToString() 比较",
-        ReplaceWith("this.contentToString() == other"),
-        DeprecationLevel.HIDDEN
-    )
-    override fun contains(sub: String): Boolean {
-        return contentToString().contains(sub)
-    }
-
-    override val size: Int = when {
-        left === EmptyMessageChain && tail !== EmptyMessageChain -> 1
-        left === EmptyMessageChain && tail === EmptyMessageChain -> 0
-        left !== EmptyMessageChain && tail === EmptyMessageChain -> 1
-        left !== EmptyMessageChain && tail !== EmptyMessageChain -> 2
-        else -> error("stub")
+    override val size: Int by lazy {
+        var size = 0
+        size += if (left is MessageChain) left.size else 1
+        size += if (tail is MessageChain) tail.size else 1
+        size
     }
 
     @OptIn(MiraiExperimentalAPI::class)

+ 114 - 100
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt

@@ -61,7 +61,6 @@ import kotlin.jvm.JvmSynthetic
  * @see HummerMessage 一些特殊的消息, 如 [闪照][FlashImage], [戳一戳][PokeMessage]
  *
  * @see MessageChain 消息链(即 `List<Message>`)
- * @see CombinedMessage 链接的两个消息
  * @see buildMessageChain 构造一个 [MessageChain]
  *
  * @see Contact.sendMessage 发送消息
@@ -104,79 +103,19 @@ interface Message {
     @Suppress("DEPRECATION_ERROR")
     @OptIn(MiraiInternalAPI::class)
     @JvmSynthetic // in java they should use `plus` instead
-    fun followedBy(tail: Message): MessageChain {
-        when {
-            this is SingleMessage && tail is SingleMessage -> {
-                if (this is ConstrainSingle<*> && tail is ConstrainSingle<*>) {
-                    if (this.key == tail.key)
-                        return SingleMessageChainImpl(tail)
-                }
-                return CombinedMessage(this, tail)
-            }
-
-            this is SingleMessage -> { // tail is not
-                tail as MessageChain
-
-                if (this is ConstrainSingle<*>) {
-                    val key = this.key
-                    if (tail.any { (it as? ConstrainSingle<*>)?.key == key }) {
-                        return tail
-                    }
-                }
-                return CombinedMessage(this, tail)
-            }
-
-            tail is SingleMessage -> {
-                this as MessageChain
-
-                if (tail is ConstrainSingle<*> && this.hasDuplicationOfConstrain(tail.key)) {
-                    val iterator = this.iterator()
-                    var tailUsed = false
-                    return MessageChainImplByCollection(
-                        constrainSingleMessagesImpl {
-                            if (iterator.hasNext()) {
-                                iterator.next()
-                            } else if (!tailUsed) {
-                                tailUsed = true
-                                tail
-                            } else null
-                        }
-                    )
-                }
-
-                return CombinedMessage(this, tail)
-            }
-
-            else -> { // both chain
-                this as MessageChain
-                tail as MessageChain
-
-                var iterator = this.iterator()
-                var tailUsed = false
-                return MessageChainImplByCollection(
-                    constrainSingleMessagesImpl {
-                        if (iterator.hasNext()) {
-                            iterator.next()
-                        } else if (!tailUsed) {
-                            tailUsed = true
-                            iterator = tail.iterator()
-                            iterator.next()
-                        } else null
-                    }
-                )
-            }
-        }
-    }
+    fun followedBy(tail: Message): MessageChain = followedByImpl(tail)
 
     /**
      * 得到包含 mirai 消息元素代码的, 易读的字符串. 如 `At(member) + "test"` 将转为 `"[mirai:at:qqId]test"`
      *
+     * 在使用消息相关 DSL 和扩展时, 一些内容比较的实现均使用的是 [contentToString] 而不是 [toString]
+     *
      * 各个 [SingleMessage] 的转换示例:
      * [PlainText]: "Hello"
      * [GroupImage]: "[mirai:image:{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png]"
      * [FriendImage]: "[mirai:image:/f8f1ab55-bf8e-4236-b55e-955848d7069f]"
      * [PokeMessage]: "[mirai:poke:1,-1]"
-     * [MessageChain]: 直接无间隔地连接所有元素.
+     * [MessageChain]: 直接无间隔地连接所有元素 (`joinToString("")`)
      *
      * @see contentToString
      */
@@ -184,8 +123,11 @@ interface Message {
 
     /**
      * 转为最接近官方格式的字符串. 如 `At(member) + "test"` 将转为 `"@群名片 test"`.
-     * 对于 [NullMessageChain], 这个函数返回空字符串 ""
-     * 对于其他 [MessageChain], 这个函数返回值同 [toString]
+     *
+     * 对于 [NullMessageChain], 这个函数返回空字符串 "";
+     * 对于其他 [MessageChain], 这个函数返回值同 [toString].
+     *
+     * 在使用消息相关 DSL 和扩展时, 一些内容比较的实现均使用的是 [contentToString] 而不是 [toString]
      */
     @SinceMirai("0.34.0")
     fun contentToString(): String
@@ -209,9 +151,9 @@ interface Message {
     @Deprecated(
         "有歧义, 自行使用 contentToString() 比较",
         ReplaceWith("this.contentToString() == other"),
-        DeprecationLevel.HIDDEN
+        DeprecationLevel.ERROR
     )
-    infix fun eq(other: Message): Boolean = this.toString() == other.toString()
+    infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
 
     /**
      * 将 [contentToString] 与 [other] 比较
@@ -221,7 +163,7 @@ interface Message {
     @Deprecated(
         "有歧义, 自行使用 contentToString() 比较",
         ReplaceWith("this.contentToString() == other"),
-        DeprecationLevel.HIDDEN
+        DeprecationLevel.ERROR
     )
     infix fun eq(other: String): Boolean = this.contentToString() == other
 
@@ -230,40 +172,40 @@ interface Message {
     @Deprecated(
         "有歧义, 自行使用 contentToString() 比较",
         ReplaceWith("this.contentToString() == other"),
-        DeprecationLevel.HIDDEN
+        DeprecationLevel.ERROR
     )
     operator fun contains(sub: String): Boolean = false
 
     @PlannedRemoval("1.0.0")
-    @Suppress("INAPPLICABLE_JVM_NAME")
+    @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
     @JvmName("followedBy")
     @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
     @JvmSynthetic
     fun followedBy1(tail: Message): CombinedMessage = this.followedByInternalForBinaryCompatibility(tail)
 
     @PlannedRemoval("1.0.0")
-    @Suppress("INAPPLICABLE_JVM_NAME")
+    @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
     @JvmName("plus")
     @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
     @JvmSynthetic
     fun plus1(another: Message): CombinedMessage = this.followedByInternalForBinaryCompatibility(another)
 
     @PlannedRemoval("1.0.0")
-    @Suppress("INAPPLICABLE_JVM_NAME")
+    @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
     @JvmName("plus")
     @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
     @JvmSynthetic
     fun plus1(another: SingleMessage): CombinedMessage = this.followedByInternalForBinaryCompatibility(another)
 
     @PlannedRemoval("1.0.0")
-    @Suppress("INAPPLICABLE_JVM_NAME")
+    @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
     @JvmName("plus")
     @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
     @JvmSynthetic
     fun plus1(another: String): CombinedMessage = this.followedByInternalForBinaryCompatibility(another.toMessage())
 
     @PlannedRemoval("1.0.0")
-    @Suppress("INAPPLICABLE_JVM_NAME")
+    @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
     @JvmName("plus")
     @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
     @JvmSynthetic
@@ -272,25 +214,6 @@ interface Message {
 }
 
 
-@OptIn(MiraiInternalAPI::class)
-private fun Message.hasDuplicationOfConstrain(key: Message.Key<*>): Boolean {
-    return when (this) {
-        is SingleMessage -> (this as? ConstrainSingle<*>)?.key == key
-        is CombinedMessage -> return this.left.hasDuplicationOfConstrain(key) || this.tail.hasDuplicationOfConstrain(key)
-        is SingleMessageChainImpl -> (this.delegate as? ConstrainSingle<*>)?.key == key
-        is MessageChainImplByCollection -> this.delegate.any { (it as? ConstrainSingle<*>)?.key == key }
-        is MessageChainImplBySequence -> this.any { (it as? ConstrainSingle<*>)?.key == key }
-        else -> error("stub")
-    }
-}
-
-@OptIn(MiraiInternalAPI::class)
-@JvmSynthetic
-@Suppress("DEPRECATION_ERROR")
-internal fun Message.followedByInternalForBinaryCompatibility(tail: Message): CombinedMessage {
-    return CombinedMessage(EmptyMessageChain, this.followedBy(tail))
-}
-
 @JvmSynthetic
 @Suppress("UNCHECKED_CAST")
 suspend inline fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> {
@@ -313,18 +236,20 @@ inline operator fun Message.times(count: Int): MessageChain = this.repeat(count)
 
 @Suppress("OverridingDeprecatedMember")
 interface SingleMessage : Message, CharSequence, Comparable<String> {
-    override operator fun contains(sub: String): Boolean = sub in this.contentToString()
+    /**
+     * 即 `sub in this.contentToString()`
+     */
+    /* final */ override operator fun contains(sub: String): Boolean = sub in this.contentToString()
 
     /**
      * 比较两个消息的 [contentToString]
      */
-    override infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
+    /* final */ override infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
 
     /**
      * 将 [contentToString] 与 [other] 比较
      */
-    override infix fun eq(other: String): Boolean = this.contentToString() == other
-
+    /* final */ override infix fun eq(other: String): Boolean = this.contentToString() == other
 }
 
 /**
@@ -360,4 +285,93 @@ interface MessageContent : SingleMessage
 @JvmSynthetic
 @Suppress("UNCHECKED_CAST")
 suspend inline fun <C : Contact> MessageChain.sendTo(contact: C): MessageReceipt<C> =
-    contact.sendMessage(this) as MessageReceipt<C>
+    contact.sendMessage(this) as MessageReceipt<C>
+
+
+/////////////////////
+/// IMPLEMENTATIONS
+//////////////////////
+
+
+@OptIn(MiraiInternalAPI::class)
+private fun Message.hasDuplicationOfConstrain(key: Message.Key<*>): Boolean {
+    return when (this) {
+        is SingleMessage -> (this as? ConstrainSingle<*>)?.key == key
+        is CombinedMessage -> return this.left.hasDuplicationOfConstrain(key) || this.tail.hasDuplicationOfConstrain(key)
+        is SingleMessageChainImpl -> (this.delegate as? ConstrainSingle<*>)?.key == key
+        is MessageChainImplByCollection -> this.delegate.any { (it as? ConstrainSingle<*>)?.key == key }
+        is MessageChainImplBySequence -> this.any { (it as? ConstrainSingle<*>)?.key == key }
+        else -> error("stub")
+    }
+}
+
+@OptIn(MiraiInternalAPI::class)
+@JvmSynthetic
+@Suppress("DEPRECATION_ERROR")
+internal fun Message.followedByInternalForBinaryCompatibility(tail: Message): CombinedMessage {
+    return CombinedMessage(EmptyMessageChain, this.followedBy(tail))
+}
+
+private fun Message.followedByImpl(tail: Message): MessageChain {
+    when {
+        this is SingleMessage && tail is SingleMessage -> {
+            if (this is ConstrainSingle<*> && tail is ConstrainSingle<*>) {
+                if (this.key == tail.key)
+                    return SingleMessageChainImpl(tail)
+            }
+            return CombinedMessage(this, tail)
+        }
+
+        this is SingleMessage -> { // tail is not
+            tail as MessageChain
+
+            if (this is ConstrainSingle<*>) {
+                val key = this.key
+                if (tail.any { (it as? ConstrainSingle<*>)?.key == key }) {
+                    return tail
+                }
+            }
+            return CombinedMessage(this, tail)
+        }
+
+        tail is SingleMessage -> {
+            this as MessageChain
+
+            if (tail is ConstrainSingle<*> && this.hasDuplicationOfConstrain(tail.key)) {
+                val iterator = this.iterator()
+                var tailUsed = false
+                return MessageChainImplByCollection(
+                    constrainSingleMessagesImpl {
+                        if (iterator.hasNext()) {
+                            iterator.next()
+                        } else if (!tailUsed) {
+                            tailUsed = true
+                            tail
+                        } else null
+                    }
+                )
+            }
+
+            return CombinedMessage(this, tail)
+        }
+
+        else -> { // both chain
+            this as MessageChain
+            tail as MessageChain
+
+            var iterator = this.iterator()
+            var tailUsed = false
+            return MessageChainImplByCollection(
+                constrainSingleMessagesImpl {
+                    if (iterator.hasNext()) {
+                        iterator.next()
+                    } else if (!tailUsed) {
+                        tailUsed = true
+                        iterator = tail.iterator()
+                        iterator.next()
+                    } else null
+                }
+            )
+        }
+    }
+}

+ 6 - 29
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt

@@ -43,10 +43,10 @@ interface MessageChain : Message, Iterable<SingleMessage> {
     @PlannedRemoval("1.0.0")
     @Deprecated(
         "有歧义, 自行使用 contentToString() 比较",
-        ReplaceWith("this.contentToString() == other"),
-        DeprecationLevel.HIDDEN
+        level = DeprecationLevel.ERROR,
+        replaceWith = ReplaceWith("this.contentToString().contains(sub)")
     )
-    override operator fun contains(sub: String): Boolean
+    /* final */ override operator fun contains(sub: String): Boolean = this.contentToString().contains(sub)
 
     /**
      * 元素数量. [EmptyMessageChain] 不参加计数.
@@ -289,17 +289,6 @@ fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
 @JvmSynthetic
 inline fun MessageChain.asMessageChain(): MessageChain = this // 避免套娃
 
-@JvmSynthetic
-@OptIn(MiraiInternalAPI::class)
-fun CombinedMessage.asMessageChain(): MessageChain {
-    @OptIn(MiraiExperimentalAPI::class)
-    if (left is SingleMessage && this.tail is SingleMessage) {
-        @Suppress("UNCHECKED_CAST")
-        return (this as Iterable<SingleMessage>).asMessageChain()
-    }
-    return (this as Iterable<Message>).asMessageChain()
-} // 避免套娃
-
 /**
  * 将 [this] [扁平化后][flatten] 委托为一个 [MessageChain]
  */
@@ -390,19 +379,11 @@ fun Message.flatten(): Sequence<SingleMessage> {
     @OptIn(MiraiInternalAPI::class)
     return when (this) {
         is MessageChain -> this.asSequence()
-        is CombinedMessage -> this.flatten() // already constrained single.
+        is CombinedMessage -> this.asSequence() // already constrained single.
         else -> sequenceOf(this as SingleMessage)
     }
 }
 
-@JvmSynthetic // make Java user happier with less methods
-@OptIn(MiraiInternalAPI::class)
-fun CombinedMessage.flatten(): Sequence<SingleMessage> {
-    // already constrained single.
-    @Suppress("UNCHECKED_CAST")
-    return (this as Iterable<SingleMessage>).asSequence()
-}
-
 @JvmSynthetic // make Java user happier with less methods
 inline fun MessageChain.flatten(): Sequence<SingleMessage> = this.asSequence() // fast path
 
@@ -410,10 +391,10 @@ inline fun MessageChain.flatten(): Sequence<SingleMessage> = this.asSequence() /
 
 
 /**
- * 不含任何元素的 [MessageChain]
+ * 不含任何元素的 [MessageChain].
  */
 object EmptyMessageChain : MessageChain, Iterator<SingleMessage> {
-    override fun contains(sub: String): Boolean = sub.isEmpty()
+
     override val size: Int get() = 0
     override fun toString(): String = ""
     override fun contentToString(): String = ""
@@ -434,7 +415,6 @@ object NullMessageChain : MessageChain {
     override fun contentToString(): String = ""
     override val size: Int get() = 0
     override fun equals(other: Any?): Boolean = other === this
-    override fun contains(sub: String): Boolean = error("accessing NullMessageChain")
     override fun iterator(): MutableIterator<SingleMessage> = error("accessing NullMessageChain")
 }
 
@@ -516,7 +496,6 @@ internal class MessageChainImplByCollection constructor(
         get() = field ?: this.delegate.joinToString("") { it.contentToString() }.also { field = it }
 
     override fun contentToString(): String = contentToStringTemp!!
-    override operator fun contains(sub: String): Boolean = sub in contentToStringTemp!!
 }
 
 /**
@@ -543,7 +522,6 @@ internal class MessageChainImplBySequence constructor(
         get() = field ?: this.joinToString("") { it.contentToString() }.also { field = it }
 
     override fun contentToString(): String = contentToStringTemp!!
-    override operator fun contains(sub: String): Boolean = sub in contentToStringTemp!!
 }
 
 /**
@@ -557,7 +535,6 @@ internal class SingleMessageChainImpl constructor(
     override fun toString(): String = this.delegate.toString()
     override fun contentToString(): String = this.delegate.contentToString()
     override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
-    override operator fun contains(sub: String): Boolean = sub in delegate
 }
 
 // endregion