Commit 3dfaa4ee authored by Him188's avatar Him188

Powerful MessageChains

parent ffe8339c
......@@ -24,15 +24,8 @@ sealed class Contact(val bot: Bot, val id: UInt) {
abstract suspend fun sendMessage(message: MessageChain)
suspend fun sendMessage(message: Message) {
if (message is MessageChain) {
return sendMessage(message)
}
return sendMessage(message.toChain())
}
suspend fun sendMessage(plain: String) = this.sendMessage(PlainText(plain))
suspend fun sendMessage(message: Message) = sendMessage(message.toChain())
suspend fun sendMessage(plain: String) = sendMessage(PlainText(plain))
abstract suspend fun sendXMLMessage(message: String)
}
......
......@@ -70,8 +70,8 @@ interface Message {
* ```
*/
fun concat(tail: Message): MessageChain =
if (tail is MessageChain) MessageChain(this).also { tail.forEach { child -> it.concat(child) } }
else MessageChain(this, tail)
if (tail is MessageChain) tail.concat(this)/*MessageChainImpl(this).also { tail.forEach { child -> it.concat(child) } }*/
else MessageChainImpl(this, tail)
infix operator fun plus(another: Message): MessageChain = this.concat(another)
infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
......@@ -129,23 +129,142 @@ inline class Face(val id: FaceID) : Message {
}
// ==================================== MessageChain ====================================
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
*/
@Suppress("FunctionName")
fun MessageChain(): MessageChain = MessageChainImpl(ArrayList(8))
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 [initialCapacity]
*/
@Suppress("FunctionName")
fun MessageChain(initialCapacity: Int): MessageChain = MessageChainImpl(ArrayList(initialCapacity))
/**
* 构造 [MessageChain]
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@Suppress("FunctionName")
fun MessageChain(vararg messages: Message): MessageChain = MessageChainImpl(messages.toMutableList())
/**
* 构造 [MessageChain]
*/
@Suppress("FunctionName")
fun MessageChain(messages: Iterable<Message>): MessageChain = MessageChainImpl(messages.toMutableList())
/**
* 构造单元素的不可修改的 [MessageChain]. 内部类实现为 [SingleMessageChain]
*
* 参数 [delegate] 不能为 [MessageChain] 的实例, 否则将会抛出异常.
* 使用 [Message.toChain] 将帮助提前处理这个问题.
*
* @param delegate 所构造的单元素 [MessageChain] 代表的 [Message]
* @throws IllegalArgumentException 当 [delegate] 为 [MessageChain] 的实例时
* @see Message.toChain 将
*/
@Suppress("FunctionName")
fun SingleMessageChain(delegate: Message): MessageChain {
require(delegate !is MessageChain) { "delegate for SingleMessageChain should not be any instance of MessageChain" }
return SingleMessageChainImpl(delegate)
}
/**
* 消息链. 即 MutableList<Message>.
* 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList], [delegate]
* 它的一般实现为 [MessageChainImpl], `null` 实现为 [NullMessageChain]
*
* 有关 [MessageChain] 的创建和连接:
* - 当任意两个不是 [MessageChain] 的 [Message] 相连接后, 将会产生一个 [MessageChain].
* - 若两个 [MessageChain] 连接, 后一个将会被添加到第一个内.
* - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内.
* - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [Message] 与一个 [MessageChain] 连接, 将会创建一个新的 [MessageChain], 并顺序添加连接时的参数.
* - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain].
*/
inline class MessageChain constructor(
interface MessageChain : Message, MutableList<Message> {
// region Message override
override val stringValue: String
override operator fun contains(sub: String): Boolean
override fun concat(tail: Message): MessageChain
// endregion
operator fun plusAssign(message: Message) {
this.concat(message)
}
operator fun plusAssign(plain: String) {
this.concat(plain.toMessage())
}
}
/**
* Null 的 [MessageChain].
* 它不包含任何元素, 也没有创建任何 list.
*
* - 所有 get 方法均抛出 [NoSuchElementException]
* - 所有 add 方法均抛出 [UnsupportedOperationException]
* - 其他判断类方法均 false 或 -1
*/
object NullMessageChain : MessageChain {
override fun subList(fromIndex: Int, toIndex: Int): MutableList<Message> = unsupported()
override val stringValue: String
get() = ""
override fun contains(sub: String): Boolean = false
override fun contains(element: Message): Boolean = false
override fun concat(tail: Message): MessageChain = MessageChainImpl(tail)
override val size: Int = 0
override fun containsAll(elements: Collection<Message>): Boolean = false
override fun get(index: Int): Message = throw NoSuchElementException()
override fun indexOf(element: Message): Int = -1
override fun isEmpty(): Boolean = true
override fun iterator(): MutableIterator<Message> = object : MutableIterator<Message> {
override fun hasNext(): Boolean = false
override fun next(): Message = throw NoSuchElementException()
override fun remove() = throw NoSuchElementException()
}
override fun lastIndexOf(element: Message): Int = -1
override fun add(element: Message): Boolean = unsupported()
override fun add(index: Int, element: Message) = unsupported()
override fun addAll(index: Int, elements: Collection<Message>): Boolean = unsupported()
override fun addAll(elements: Collection<Message>): Boolean = unsupported()
override fun clear() {}
override fun listIterator(): MutableListIterator<Message> = object : MutableListIterator<Message> {
override fun hasPrevious(): Boolean = false
override fun nextIndex(): Int = -1
override fun previous(): Message = throw NoSuchElementException()
override fun previousIndex(): Int = -1
override fun add(element: Message) = unsupported()
override fun hasNext(): Boolean = false
override fun next(): Message = throw NoSuchElementException()
override fun remove() = throw NoSuchElementException()
override fun set(element: Message) = unsupported()
}
override fun listIterator(index: Int): MutableListIterator<Message> = unsupported()
override fun remove(element: Message): Boolean = false
override fun removeAll(elements: Collection<Message>): Boolean = false
override fun removeAt(index: Int): Message = throw NoSuchElementException()
override fun retainAll(elements: Collection<Message>): Boolean = false
override fun set(index: Int, element: Message): Message = unsupported()
private fun unsupported(): Nothing = throw UnsupportedOperationException()
}
/**
* [MessageChain] 实现
* 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList].
*/
internal inline class MessageChainImpl constructor(
/**
* Elements will not be instances of [MessageChain]
*/
private val delegate: MutableList<Message>
) : Message, MutableList<Message> {
) : Message, MutableList<Message>, MessageChain {
constructor() : this(ArrayList(8))
constructor(initialCapacity: Int) : this(ArrayList(initialCapacity))
constructor(vararg messages: Message) : this(messages.toMutableList())
constructor(messages: Iterable<Message>) : this(messages.toMutableList())
......@@ -154,33 +273,20 @@ inline class MessageChain constructor(
override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) }
override fun concat(tail: Message): MessageChain {
if (tail is MessageChain) tail.delegate.forEach { child -> this.concat(child) }
if (tail is MessageChain) tail.forEach { child -> this.concat(child) }
else this.delegate.add(tail)
return this
}
// endregion
/**
* 获取第一个 [M] 类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
inline fun <reified M : Message> first(): Message = this.first { M::class.isInstance(it) }
/**
* 获取第一个 [M] 类型的实例
*/
inline fun <reified M : Message> firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
operator fun plusAssign(message: Message) {
// endregion
override operator fun plusAssign(message: Message) {
this.concat(message)
}
operator fun plusAssign(plain: String) {
override operator fun plusAssign(plain: String) {
this.concat(plain.toMessage())
}
// region MutableList override
override fun containsAll(elements: Collection<Message>): Boolean = delegate.containsAll(elements)
......@@ -206,3 +312,95 @@ inline class MessageChain constructor(
override val size: Int get() = delegate.size
// endregion
}
/**
* 单个成员的不可修改的 [MessageChain].
* 在连接时将会把它当做一个普通 [Message] 看待.
*/
internal inline class SingleMessageChainImpl(
private val delegate: Message
) : Message, MutableList<Message>, MessageChain {
// region Message override
override val stringValue: String get() = this.delegate.stringValue
override operator fun contains(sub: String): Boolean = delegate.contains(sub)
override fun concat(tail: Message): MessageChain {
if (tail is MessageChain) tail.forEach { child -> this.concat(child) }
else MessageChain(delegate, tail)
return this
}
// endregion
// region MutableList override
override fun containsAll(elements: Collection<Message>): Boolean = elements.all { it === delegate }
override operator fun get(index: Int): Message = if (index == 0) delegate else throw NoSuchElementException()
override fun indexOf(element: Message): Int = if (delegate === element) 0 else -1
override fun isEmpty(): Boolean = false
override fun lastIndexOf(element: Message): Int = if (delegate === element) 0 else -1
override fun add(element: Message): Boolean = throw UnsupportedOperationException()
override fun add(index: Int, element: Message) = throw UnsupportedOperationException()
override fun addAll(index: Int, elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun clear() = throw UnsupportedOperationException()
override fun listIterator(): MutableListIterator<Message> = object : MutableListIterator<Message> {
private var hasNext = true
override fun hasPrevious(): Boolean = false
override fun nextIndex(): Int = if (hasNext) 0 else -1
override fun previous(): Message = throw NoSuchElementException()
override fun previousIndex(): Int = -1
override fun add(element: Message) = throw UnsupportedOperationException()
override fun hasNext(): Boolean = !hasNext
override fun next(): Message =
if (hasNext) {
hasNext = false
this@SingleMessageChainImpl
} else throw NoSuchElementException()
override fun remove() = throw UnsupportedOperationException()
override fun set(element: Message) = throw UnsupportedOperationException()
}
override fun listIterator(index: Int): MutableListIterator<Message> = throw UnsupportedOperationException()
override fun remove(element: Message): Boolean = throw UnsupportedOperationException()
override fun removeAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun removeAt(index: Int): Message = throw UnsupportedOperationException()
override fun retainAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun set(index: Int, element: Message): Message = throw UnsupportedOperationException()
override fun subList(fromIndex: Int, toIndex: Int): MutableList<Message> {
return if (fromIndex == 0) when (toIndex) {
1 -> mutableListOf<Message>(this)
0 -> mutableListOf()
else -> throw UnsupportedOperationException()
}
else throw UnsupportedOperationException()
}
override fun iterator(): MutableIterator<Message> = object : MutableIterator<Message> {
private var hasNext = true
override fun hasNext(): Boolean = !hasNext
override fun next(): Message =
if (hasNext) {
hasNext = false
this@SingleMessageChainImpl
} else throw NoSuchElementException()
override fun remove() = throw UnsupportedOperationException()
}
override operator fun contains(element: Message): Boolean = element === delegate
override val size: Int get() = 1
// endregion
}
/**
* 获取第一个 [M] 类型的实例
*/
inline fun <reified M : Message> MessageChain.firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
/**
* 获取第一个 [M] 类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
inline fun <reified M : Message> MessageChain.first(): Message = this.first { M::class.isInstance(it) }
\ No newline at end of file
......@@ -7,9 +7,20 @@ package net.mamoe.mirai.message
fun String.toMessage(): PlainText = PlainText(this)
/**
* 构造 [MessageChain]
* 得到包含 [this] 的 [MessageChain].
* 若 [this] 为 [MessageChain] 将直接返回 this
* 否则将调用 [SingleMessageChain] 构造一个唯一成员不可修改的 [SingleMessageChainImpl]
*
* @see SingleMessageChain
* @see SingleMessageChainImpl
*/
fun Message.toChain(): MessageChain = if (this is MessageChain) this else SingleMessageChain(this)
/**
* 以 [this] 为代表 (delegate) 构造 [SingleMessageChain].
* @throws IllegalArgumentException 当 [this] 为 [MessageChain] 的实例时
*/
fun Message.toChain(): MessageChain = if (this is MessageChain) this else MessageChain(this)
fun Message.singleChain(): MessageChain = SingleMessageChain(this)
/**
* 构造 [MessageChain]
......
......@@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.NullMessageChain
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.utils.io.*
import kotlin.properties.Delegates
......@@ -26,7 +27,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
* 发送方权限.
*/
lateinit var senderPermission: SenderPermission
var message: MessageChain by Delegates.notNull()
var message: MessageChain = NullMessageChain
override fun decode() = with(input) {
discardExact(31)
......
......@@ -36,15 +36,17 @@ private object IgnoreIdList : List<String> by listOf(
"EMPTY_ID_HEX",
"input",
"output",
"this\$0",
"\$\$delegatedProperties",
"UninitializedByteReadPacket",
"sessionKey"
)
internal actual fun Packet.packetToString(): String = PacketNameFormatter.adjustName(this::class.simpleName + "(${this.idHexString})") + this::class.java.allDeclaredFields
.filterNot { it.name in IgnoreIdList || /*"delegate" in it.name||*/ "$" in it.name }
.filterNot { it.name in IgnoreIdList /*|| "delegate" in it.name|| "$" in it.name */ }
.joinToString(", ", "{", "}") {
it.isAccessible = true
it.name + "=" + it.get(this).let { value ->
it.name.replace("\$delegate", "") + "=" + it.get(this).let { value ->
when (value) {
null -> null
is ByteArray -> value.toUHexString()
......@@ -52,6 +54,7 @@ internal actual fun Packet.packetToString(): String = PacketNameFormatter.adjust
is ByteReadPacket -> "[ByteReadPacket(${value.remaining})]"
//is ByteReadPacket -> value.copy().readBytes().toUHexString()
is IoBuffer -> "[IoBuffer(${value.readRemaining})]"
is Lazy<*> -> "[Lazy]"
else -> value.toString()
}
}
......
......@@ -15,6 +15,7 @@ import net.mamoe.mirai.login
import net.mamoe.mirai.message.Image
import net.mamoe.mirai.message.ImageId
import net.mamoe.mirai.message.PlainText
import net.mamoe.mirai.message.firstOrNull
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.network.protocol.tim.packet.uploadImage
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment