|
|
@@ -14,6 +14,7 @@
|
|
|
package net.mamoe.mirai.message.data
|
|
|
|
|
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
|
|
+import net.mamoe.mirai.utils.SinceMirai
|
|
|
import kotlin.jvm.JvmMultifileClass
|
|
|
import kotlin.jvm.JvmName
|
|
|
import kotlin.jvm.JvmSynthetic
|
|
|
@@ -53,35 +54,14 @@ class MessageChainBuilder private constructor(
|
|
|
constructor() : this(mutableListOf())
|
|
|
constructor(initialSize: Int) : this(ArrayList<SingleMessage>(initialSize))
|
|
|
|
|
|
- private var firstConstrainSingleIndex = -1
|
|
|
-
|
|
|
- private fun addAndCheckConstrainSingle(element: SingleMessage): Boolean {
|
|
|
- if (element is ConstrainSingle<*>) {
|
|
|
- if (firstConstrainSingleIndex == -1) {
|
|
|
- firstConstrainSingleIndex = container.size
|
|
|
- return container.add(element)
|
|
|
- }
|
|
|
- val key = element.key
|
|
|
-
|
|
|
- val index = container.indexOfFirst(firstConstrainSingleIndex) { it is ConstrainSingle<*> && it.key == key }
|
|
|
- if (index != -1) {
|
|
|
- container[index] = element
|
|
|
- } else {
|
|
|
- container.add(element)
|
|
|
- }
|
|
|
-
|
|
|
- return true
|
|
|
- } else {
|
|
|
- return container.add(element)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
override fun add(element: SingleMessage): Boolean {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
return addAndCheckConstrainSingle(element)
|
|
|
}
|
|
|
|
|
|
fun add(element: Message): Boolean {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
|
return when (element) {
|
|
|
@@ -93,44 +73,113 @@ class MessageChainBuilder private constructor(
|
|
|
}
|
|
|
|
|
|
override fun addAll(elements: Collection<SingleMessage>): Boolean {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
return addAll(elements.flatten())
|
|
|
}
|
|
|
|
|
|
@JvmName("addAllFlatten") // erased generic type cause declaration clash
|
|
|
fun addAll(elements: Collection<Message>): Boolean {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
return addAll(elements.flatten())
|
|
|
}
|
|
|
|
|
|
operator fun Message.unaryPlus() {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
add(this)
|
|
|
}
|
|
|
|
|
|
|
|
|
operator fun String.unaryPlus() {
|
|
|
+ checkBuilt()
|
|
|
add(this)
|
|
|
}
|
|
|
|
|
|
operator fun plusAssign(plain: String) {
|
|
|
+ checkBuilt()
|
|
|
withCache { append(plain) }
|
|
|
}
|
|
|
|
|
|
operator fun plusAssign(message: Message) {
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
this.add(message)
|
|
|
}
|
|
|
|
|
|
operator fun plusAssign(message: SingleMessage) { // avoid resolution ambiguity
|
|
|
+ checkBuilt()
|
|
|
flushCache()
|
|
|
this.add(message)
|
|
|
}
|
|
|
|
|
|
fun add(plain: String) {
|
|
|
+ checkBuilt()
|
|
|
withCache { append(plain) }
|
|
|
}
|
|
|
|
|
|
+ operator fun plusAssign(charSequence: CharSequence) {
|
|
|
+ checkBuilt()
|
|
|
+ withCache { append(charSequence) }
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun append(value: Char): MessageChainBuilder = withCache { append(value) }
|
|
|
+ override fun append(value: CharSequence?): MessageChainBuilder = withCache { append(value) }
|
|
|
+ override fun append(value: CharSequence?, startIndex: Int, endIndex: Int): MessageChainBuilder =
|
|
|
+ withCache { append(value, startIndex, endIndex) }
|
|
|
+
|
|
|
+ fun append(message: Message): MessageChainBuilder = apply { add(message) }
|
|
|
+ fun append(message: SingleMessage): MessageChainBuilder = apply { add(message) }
|
|
|
+
|
|
|
+ // avoid resolution to extensions
|
|
|
+ fun asMessageChain(): MessageChain {
|
|
|
+ built = true
|
|
|
+ this.flushCache()
|
|
|
+ return MessageChainImplByCollection(this) // fast-path, no need to constrain
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 同 [asMessageChain] */
|
|
|
+ fun build(): MessageChain = asMessageChain()
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将所有已有元素引用复制到一个新的 [MessageChainBuilder]
|
|
|
+ */
|
|
|
+ @SinceMirai("0.38.0")
|
|
|
+ fun copy(): MessageChainBuilder {
|
|
|
+ return MessageChainBuilder(container.toMutableList())
|
|
|
+ }
|
|
|
+
|
|
|
+ ///////
|
|
|
+ // FOR IMMUTABLE SAFETY
|
|
|
+
|
|
|
+ override fun remove(element: SingleMessage): Boolean {
|
|
|
+ checkBuilt()
|
|
|
+ return container.remove(element)
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun removeAll(elements: Collection<SingleMessage>): Boolean {
|
|
|
+ checkBuilt()
|
|
|
+ return container.removeAll(elements)
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun removeAt(index: Int): SingleMessage {
|
|
|
+ checkBuilt()
|
|
|
+ return container.removeAt(index)
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun clear() {
|
|
|
+ checkBuilt()
|
|
|
+ return container.clear()
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun set(index: Int, element: SingleMessage): SingleMessage {
|
|
|
+ checkBuilt()
|
|
|
+ return container.set(index, element)
|
|
|
+ }
|
|
|
+
|
|
|
+ ///////
|
|
|
+ // IMPLEMENTATION
|
|
|
private var cache: StringBuilder? = null
|
|
|
private fun flushCache() {
|
|
|
cache?.let {
|
|
|
@@ -140,6 +189,7 @@ class MessageChainBuilder private constructor(
|
|
|
}
|
|
|
|
|
|
private inline fun withCache(block: StringBuilder.() -> Unit): MessageChainBuilder {
|
|
|
+ checkBuilt()
|
|
|
if (cache == null) {
|
|
|
cache = StringBuilder().apply(block)
|
|
|
} else {
|
|
|
@@ -148,20 +198,29 @@ class MessageChainBuilder private constructor(
|
|
|
return this
|
|
|
}
|
|
|
|
|
|
- operator fun plusAssign(charSequence: CharSequence) {
|
|
|
- withCache { append(charSequence) }
|
|
|
- }
|
|
|
+ private var built = false
|
|
|
+ private fun checkBuilt() = check(!built) { "MessageChainBuilder is already built therefore can't modify" }
|
|
|
|
|
|
- override fun append(value: Char): Appendable = withCache { append(value) }
|
|
|
- override fun append(value: CharSequence?): Appendable = withCache { append(value) }
|
|
|
- override fun append(value: CharSequence?, startIndex: Int, endIndex: Int) =
|
|
|
- withCache { append(value, startIndex, endIndex) }
|
|
|
+ private var firstConstrainSingleIndex = -1
|
|
|
|
|
|
- fun asMessageChain(): MessageChain {
|
|
|
- this.flushCache()
|
|
|
- return MessageChainImplByCollection(this) // fast-path, no need to constrain
|
|
|
- }
|
|
|
+ private fun addAndCheckConstrainSingle(element: SingleMessage): Boolean {
|
|
|
+ if (element is ConstrainSingle<*>) {
|
|
|
+ if (firstConstrainSingleIndex == -1) {
|
|
|
+ firstConstrainSingleIndex = container.size
|
|
|
+ return container.add(element)
|
|
|
+ }
|
|
|
+ val key = element.key
|
|
|
|
|
|
- /** 同 [asMessageChain] */
|
|
|
- fun build(): MessageChain = asMessageChain()
|
|
|
+ val index = container.indexOfFirst(firstConstrainSingleIndex) { it is ConstrainSingle<*> && it.key == key }
|
|
|
+ if (index != -1) {
|
|
|
+ container[index] = element
|
|
|
+ } else {
|
|
|
+ container.add(element)
|
|
|
+ }
|
|
|
+
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ return container.add(element)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|