From 6b792e3ba60ba3a4693e91d30c30f04da1f8673a Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Fri, 11 Dec 2020 14:53:47 +0800
Subject: [PATCH] Simplify MessageChain implementations

---
 .../kotlin/message/data/CombinedMessage.kt    | 48 ++++++------
 .../kotlin/message/data/MessageChain.kt       |  6 +-
 .../message/data/MessageChainBuilder.kt       |  2 +-
 .../commonMain/kotlin/message/data/impl.kt    | 75 ++++++++-----------
 .../message.data/CombinedMessageTest.kt       |  4 +-
 .../message.data/ConstrainSingleTest.kt       | 21 +-----
 6 files changed, 62 insertions(+), 94 deletions(-)

diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/CombinedMessage.kt b/mirai-core-api/src/commonMain/kotlin/message/data/CombinedMessage.kt
index a8c008a03..bc3069db8 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/CombinedMessage.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/CombinedMessage.kt
@@ -12,31 +12,29 @@
 
 package net.mamoe.mirai.message.data
 
-import kotlinx.serialization.Serializable
-import kotlin.LazyThreadSafetyMode.NONE
-
-/**
- * 快速链接的两个消息 (避免构造新的 list).
- *
- * 不要直接构造 [CombinedMessage], 使用 [Message.plus]
- * 要连接多个 [Message], 使用 [buildMessageChain]
- *
- * @see Message.plus
- *
- * Left-biased list
- */
-@Serializable
-internal data class CombinedMessage
-internal constructor(
-    @JvmField internal val left: Message, // 必须已经完成 constrain single
-    @JvmField internal val tail: Message
-) : Message, MessageChain, List<SingleMessage> by (left.flatten() + tail.flatten()).toList() {
-    private val toStringCache: String by lazy(NONE) { left.contentToString() + tail.contentToString() }
-    override fun toString(): String = toStringCache
-
-    private val contentToStringCache: String by lazy(NONE) { left.contentToString() + tail.contentToString() }
-    override fun contentToString(): String = contentToStringCache
-}
+//
+///**
+// * 快速链接的两个消息 (避免构造新的 list).
+// *
+// * 不要直接构造 [CombinedMessage], 使用 [Message.plus]
+// * 要连接多个 [Message], 使用 [buildMessageChain]
+// *
+// * @see Message.plus
+// *
+// * Left-biased list
+// */
+//@Serializable
+//internal data class CombinedMessage
+//internal constructor(
+//    @JvmField internal val left: Message, // 必须已经完成 constrain single
+//    @JvmField internal val tail: Message
+//) : Message, MessageChain, List<SingleMessage> by (left.flatten() + tail.flatten()).toList() {
+//    private val toStringCache: String by lazy(NONE) { left.contentToString() + tail.contentToString() }
+//    override fun toString(): String = toStringCache
+//
+//    private val contentToStringCache: String by lazy(NONE) { left.contentToString() + tail.contentToString() }
+//    override fun contentToString(): String = contentToStringCache
+//}
 
 /*
 @JvmSynthetic
diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
index 753d5b44b..bdd9fff44 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
@@ -291,7 +291,6 @@ public inline fun messageChainOf(vararg messages: Message): MessageChain = messa
 @Suppress("UNCHECKED_CAST")
 public fun Message.asMessageChain(): MessageChain = when (this) {
     is MessageChain -> this
-    is CombinedMessage -> (this as Iterable<Message>).asMessageChain()
     else -> SingleMessageChainImpl(this as SingleMessage)
 }
 
@@ -306,7 +305,7 @@ public fun SingleMessage.asMessageChain(): MessageChain = SingleMessageChainImpl
  */
 @JvmSynthetic
 public fun Collection<SingleMessage>.asMessageChain(): MessageChain =
-    MessageChainImplByCollection(this.constrainSingleMessages())
+    MessageChainImpl(this.constrainSingleMessages())
 
 /**
  * 将 [this] [扁平化后][flatten] 委托为一个 [MessageChain]
@@ -332,7 +331,7 @@ public fun Collection<Message>.asMessageChain(): MessageChain = MessageChainImpl
  */
 @JvmSynthetic
 public fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
-    MessageChainImplByCollection(this.constrainSingleMessages())
+    MessageChainImpl(this.constrainSingleMessages())
 
 @JvmSynthetic
 public inline fun MessageChain.asMessageChain(): MessageChain = this // 避免套娃
@@ -421,7 +420,6 @@ public inline fun Array<out SingleMessage>.flatten(): Sequence<SingleMessage> =
 public fun Message.flatten(): Sequence<SingleMessage> {
     return when (this) {
         is MessageChain -> this.asSequence()
-        is CombinedMessage -> this.asSequence() // already constrained single.
         else -> sequenceOf(this as SingleMessage)
     }
 }
diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChainBuilder.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChainBuilder.kt
index 01e19feed..8040c623f 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChainBuilder.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChainBuilder.kt
@@ -148,7 +148,7 @@ public open class MessageChainBuilder private constructor(
     public fun asMessageChain(): MessageChain {
         built = true
         this.flushCache()
-        return MessageChainImplByCollection(this.constrainSingleMessages())
+        return MessageChainImpl(this.constrainSingleMessages())
     }
 
     /** 同 [asMessageChain] */
diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt b/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt
index 492bef04a..4f035ad87 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt
@@ -13,6 +13,7 @@
 
 package net.mamoe.mirai.message.data
 
+import kotlinx.serialization.Serializable
 import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1
 import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
 import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
@@ -25,15 +26,16 @@ import kotlin.native.concurrent.SharedImmutable
 //// IMPLEMENTATIONS ////
 /////////////////////////
 
+@Suppress("unused", "UNUSED_PARAMETER")
 private fun Message.hasDuplicationOfConstrain(key: MessageKey<*>): 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")
-    }
+    return true
+    /*
+     return when (this) {
+         is SingleMessage -> (this as? ConstrainSingle)?.key == key
+         is CombinedMessage -> return this.left.hasDuplicationOfConstrain(key) || this.tail.hasDuplicationOfConstrain(key)
+         is MessageChainImplByCollection -> this.delegate.any { (it as? ConstrainSingle)?.key == key }
+         else -> error("stub")
+     }*/
 }
 
 //@JvmSynthetic
@@ -64,6 +66,8 @@ private fun Message.hasDuplicationOfConstrain(key: MessageKey<*>): Boolean {
 
 @JvmSynthetic
 internal fun Message.followedByImpl(tail: Message): MessageChain {
+    return MessageChainImplBySequence(this.flatten() + tail.flatten())
+    /*
     when {
         this is SingleMessage && tail is SingleMessage -> {
             if (this is ConstrainSingle && tail is ConstrainSingle) {
@@ -103,7 +107,7 @@ internal fun Message.followedByImpl(tail: Message): MessageChain {
                 constrainSingleMessagesImpl(this.asSequence() + tail)
             )
         }
-    }
+    }*/
 }
 
 
@@ -162,49 +166,36 @@ internal fun <M : SingleMessage> MessageChain.getImpl(key: MessageKey<M>): M? {
 /**
  * 使用 [Collection] 作为委托的 [MessageChain]
  */
-internal class MessageChainImplByCollection constructor(
+@Serializable
+internal data class MessageChainImpl constructor(
+    @JvmField
     internal val delegate: List<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable
 ) : Message, MessageChain, List<SingleMessage> by delegate {
     override val size: Int get() = delegate.size
     override fun iterator(): Iterator<SingleMessage> = delegate.iterator()
 
-    private var toStringTemp: String? = null
-        get() = field ?: this.delegate.joinToString("") { it.toString() }.also { field = it }
+    private val toStringTemp: String by lazy { this.delegate.joinToString("") { it.toString() } }
+    override fun toString(): String = toStringTemp
 
-    override fun toString(): String = toStringTemp!!
-
-    private var contentToStringTemp: String? = null
-        get() = field ?: this.delegate.joinToString("") { it.contentToString() }.also { field = it }
-
-    override fun contentToString(): String = contentToStringTemp!!
+    private val contentToStringTemp: String by lazy { this.delegate.joinToString("") { it.contentToString() } }
+    override fun contentToString(): String = contentToStringTemp
 }
 
-/**
- * 使用 [Iterable] 作为委托的 [MessageChain]
- */
-internal class MessageChainImplBySequence constructor(
+@Suppress("FunctionName")
+internal fun CombinedMessage(
+    left: Message,
+    tail: Message
+): MessageChain = MessageChainImplBySequence(left.flatten() + tail.flatten())
+
+@Suppress("FunctionName") // source compatibility with 1.x
+internal fun MessageChainImplBySequence(
     delegate: Sequence<SingleMessage> // 可以有重复 ConstrainSingle
-) : Message, Iterable<SingleMessage>, MessageChain, List<SingleMessage> by delegate.constrainSingleMessages() {
-    private var toStringTemp: String? = null
-        get() = field ?: this.joinToString("") { it.toString() }.also { field = it }
+): MessageChain = MessageChainImpl(delegate.constrainSingleMessages())
 
-    override fun toString(): String = toStringTemp!!
-
-    private var contentToStringTemp: String? = null
-        get() = field ?: this.joinToString("") { it.contentToString() }.also { field = it }
-
-    override fun contentToString(): String = contentToStringTemp!!
-}
-
-/**
- * 单个 [SingleMessage] 作为 [MessageChain]
- */
-internal class SingleMessageChainImpl constructor(
-    internal val delegate: SingleMessage
-) : Message, MessageChain, List<SingleMessage> by listOf(delegate) {
-    override fun toString(): String = this.delegate.toString()
-    override fun contentToString(): String = this.delegate.contentToString()
-}
+@Suppress("FunctionName")
+internal fun SingleMessageChainImpl(
+    delegate: SingleMessage
+): MessageChain = MessageChainImpl(listOf(delegate))
 
 
 //////////////////////
diff --git a/mirai-core-api/src/commonTest/kotlin/message.data/CombinedMessageTest.kt b/mirai-core-api/src/commonTest/kotlin/message.data/CombinedMessageTest.kt
index 41a1ff741..45438afe5 100644
--- a/mirai-core-api/src/commonTest/kotlin/message.data/CombinedMessageTest.kt
+++ b/mirai-core-api/src/commonTest/kotlin/message.data/CombinedMessageTest.kt
@@ -22,7 +22,7 @@ internal class CombinedMessageTest {
 
         assertEquals(
             "Hello World",
-            (message as CombinedMessage).asSequence().joinToString(separator = "")
+            message.flatten().joinToString(separator = "")
         )
     }
 
@@ -37,7 +37,7 @@ internal class CombinedMessageTest {
 
         assertEquals(
             "Hello World",
-            (message as CombinedMessage).asSequence().joinToString(separator = "")
+            message.flatten().joinToString(separator = "")
         )
     }
 }
diff --git a/mirai-core-api/src/commonTest/kotlin/message.data/ConstrainSingleTest.kt b/mirai-core-api/src/commonTest/kotlin/message.data/ConstrainSingleTest.kt
index 06f3d6cde..c6822299b 100644
--- a/mirai-core-api/src/commonTest/kotlin/message.data/ConstrainSingleTest.kt
+++ b/mirai-core-api/src/commonTest/kotlin/message.data/ConstrainSingleTest.kt
@@ -30,16 +30,6 @@ internal class TestConstrainSingleMessage : ConstrainSingle, Any() {
 internal class ConstrainSingleTest {
 
 
-    @Test
-    fun testCombine() {
-        val result = PlainText("te") + PlainText("st")
-        assertTrue(result is CombinedMessage)
-        assertEquals("te", result.left.contentToString())
-        assertEquals("st", result.tail.contentToString())
-        assertEquals(2, result.size)
-        assertEquals("test", result.contentToString())
-    }
-
     @Test
     fun testSinglePlusChain() {
         val result = PlainText("te") + buildMessageChain {
@@ -63,15 +53,6 @@ internal class ConstrainSingleTest {
         assertTrue { result.first() is TestConstrainSingleMessage }
     }
 
-    @Test
-    fun testSinglePlusSingle() {
-        val new = TestConstrainSingleMessage()
-        val combined = (TestConstrainSingleMessage() + new)
-
-        assertTrue(combined is SingleMessageChainImpl)
-        assertSame(new, combined.delegate)
-    }
-
     @Test
     fun testChainPlusSingle() {
         val new = TestConstrainSingleMessage()
@@ -92,7 +73,7 @@ internal class ConstrainSingleTest {
 
         assertEquals(7, result.size)
         assertEquals(" [OK]ss p test", result.contentToString())
-        result as MessageChainImplByCollection
+        result as MessageChainImpl
         assertSame(new, result.delegate.toTypedArray()[2])
     }