mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-09 08:46:58 +08:00
Make CombinedMessage internal
This commit is contained in:
parent
b8b749bf65
commit
4184b5f7d9
@ -14,7 +14,6 @@ package net.mamoe.mirai.message.data
|
|||||||
|
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
import net.mamoe.mirai.utils.PlannedRemoval
|
|
||||||
import kotlin.jvm.JvmMultifileClass
|
import kotlin.jvm.JvmMultifileClass
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
@ -29,8 +28,7 @@ import kotlin.jvm.JvmSynthetic
|
|||||||
*
|
*
|
||||||
* Left-biased list
|
* Left-biased list
|
||||||
*/
|
*/
|
||||||
@MiraiInternalAPI("this API is going to be internal")
|
internal class CombinedMessage
|
||||||
class CombinedMessage
|
|
||||||
internal constructor(
|
internal constructor(
|
||||||
internal val left: Message, // 必须已经完成 constrain single
|
internal val left: Message, // 必须已经完成 constrain single
|
||||||
internal val tail: Message
|
internal val tail: Message
|
||||||
@ -44,22 +42,11 @@ internal constructor(
|
|||||||
return asSequence().iterator()
|
return asSequence().iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
@PlannedRemoval("1.0.0")
|
override val size: Int by lazy {
|
||||||
@Deprecated(
|
var size = 0
|
||||||
"有歧义, 自行使用 contentToString() 比较",
|
size += if (left is MessageChain) left.size else 1
|
||||||
ReplaceWith("this.contentToString() == other"),
|
size += if (tail is MessageChain) tail.size else 1
|
||||||
DeprecationLevel.HIDDEN
|
size
|
||||||
)
|
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(MiraiExperimentalAPI::class)
|
@OptIn(MiraiExperimentalAPI::class)
|
||||||
|
@ -61,7 +61,6 @@ import kotlin.jvm.JvmSynthetic
|
|||||||
* @see HummerMessage 一些特殊的消息, 如 [闪照][FlashImage], [戳一戳][PokeMessage]
|
* @see HummerMessage 一些特殊的消息, 如 [闪照][FlashImage], [戳一戳][PokeMessage]
|
||||||
*
|
*
|
||||||
* @see MessageChain 消息链(即 `List<Message>`)
|
* @see MessageChain 消息链(即 `List<Message>`)
|
||||||
* @see CombinedMessage 链接的两个消息
|
|
||||||
* @see buildMessageChain 构造一个 [MessageChain]
|
* @see buildMessageChain 构造一个 [MessageChain]
|
||||||
*
|
*
|
||||||
* @see Contact.sendMessage 发送消息
|
* @see Contact.sendMessage 发送消息
|
||||||
@ -104,7 +103,216 @@ interface Message {
|
|||||||
@Suppress("DEPRECATION_ERROR")
|
@Suppress("DEPRECATION_ERROR")
|
||||||
@OptIn(MiraiInternalAPI::class)
|
@OptIn(MiraiInternalAPI::class)
|
||||||
@JvmSynthetic // in java they should use `plus` instead
|
@JvmSynthetic // in java they should use `plus` instead
|
||||||
fun followedBy(tail: Message): MessageChain {
|
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]: 直接无间隔地连接所有元素 (`joinToString("")`)
|
||||||
|
*
|
||||||
|
* @see contentToString
|
||||||
|
*/
|
||||||
|
override fun toString(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转为最接近官方格式的字符串. 如 `At(member) + "test"` 将转为 `"@群名片 test"`.
|
||||||
|
*
|
||||||
|
* 对于 [NullMessageChain], 这个函数返回空字符串 "";
|
||||||
|
* 对于其他 [MessageChain], 这个函数返回值同 [toString].
|
||||||
|
*
|
||||||
|
* 在使用消息相关 DSL 和扩展时, 一些内容比较的实现均使用的是 [contentToString] 而不是 [toString]
|
||||||
|
*/
|
||||||
|
@SinceMirai("0.34.0")
|
||||||
|
fun contentToString(): String
|
||||||
|
|
||||||
|
operator fun plus(another: Message): MessageChain = this.followedBy(another)
|
||||||
|
|
||||||
|
// don't remove! avoid resolution ambiguity between `CharSequence` and `Message`
|
||||||
|
operator fun plus(another: SingleMessage): MessageChain = this.followedBy(another)
|
||||||
|
|
||||||
|
operator fun plus(another: String): MessageChain = this.followedBy(another.toMessage())
|
||||||
|
|
||||||
|
// `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
|
||||||
|
operator fun plus(another: CharSequence): MessageChain = this.followedBy(another.toString().toMessage())
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// FOR BINARY COMPATIBILITY UNTIL 1.0.0
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
@PlannedRemoval("1.0.0")
|
||||||
|
@JvmSynthetic
|
||||||
|
@Deprecated(
|
||||||
|
"有歧义, 自行使用 contentToString() 比较",
|
||||||
|
ReplaceWith("this.contentToString() == other"),
|
||||||
|
DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 [contentToString] 与 [other] 比较
|
||||||
|
*/
|
||||||
|
@PlannedRemoval("1.0.0")
|
||||||
|
@JvmSynthetic
|
||||||
|
@Deprecated(
|
||||||
|
"有歧义, 自行使用 contentToString() 比较",
|
||||||
|
ReplaceWith("this.contentToString() == other"),
|
||||||
|
DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
infix fun eq(other: String): Boolean = this.contentToString() == other
|
||||||
|
|
||||||
|
@PlannedRemoval("1.0.0")
|
||||||
|
@JvmSynthetic
|
||||||
|
@Deprecated(
|
||||||
|
"有歧义, 自行使用 contentToString() 比较",
|
||||||
|
ReplaceWith("this.contentToString() == other"),
|
||||||
|
DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
operator fun contains(sub: String): Boolean = false
|
||||||
|
|
||||||
|
@PlannedRemoval("1.0.0")
|
||||||
|
@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", "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", "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", "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", "EXPOSED_FUNCTION_RETURN_TYPE")
|
||||||
|
@JvmName("plus")
|
||||||
|
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
|
||||||
|
@JvmSynthetic
|
||||||
|
fun plus1(another: CharSequence): CombinedMessage =
|
||||||
|
this.followedByInternalForBinaryCompatibility(another.toString().toMessage())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
suspend inline fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> {
|
||||||
|
return contact.sendMessage(this) as MessageReceipt<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline: for future removal
|
||||||
|
inline fun Message.repeat(count: Int): MessageChain {
|
||||||
|
if (this is ConstrainSingle<*>) {
|
||||||
|
// fast-path
|
||||||
|
return SingleMessageChainImpl(this)
|
||||||
|
}
|
||||||
|
return buildMessageChain(count) {
|
||||||
|
add(this@repeat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
inline operator fun Message.times(count: Int): MessageChain = this.repeat(count)
|
||||||
|
|
||||||
|
@Suppress("OverridingDeprecatedMember")
|
||||||
|
interface SingleMessage : Message, CharSequence, Comparable<String> {
|
||||||
|
/**
|
||||||
|
* 即 `sub in this.contentToString()`
|
||||||
|
*/
|
||||||
|
/* final */ override operator fun contains(sub: String): Boolean = sub in this.contentToString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个消息的 [contentToString]
|
||||||
|
*/
|
||||||
|
/* final */ override infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 [contentToString] 与 [other] 比较
|
||||||
|
*/
|
||||||
|
/* final */ override infix fun eq(other: String): Boolean = this.contentToString() == other
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息元数据, 即不含内容的元素.
|
||||||
|
* 包括: [MessageSource]
|
||||||
|
*/
|
||||||
|
interface MessageMetadata : SingleMessage {
|
||||||
|
override val length: Int get() = 0
|
||||||
|
override fun get(index: Int): Char = ""[index] // produce uniform exception
|
||||||
|
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = "".subSequence(startIndex, endIndex)
|
||||||
|
override fun compareTo(other: String): Int = "".compareTo(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 约束一个 [MessageChain] 中只存在这一种类型的元素. 新元素将会替换旧元素, 保持原顺序.
|
||||||
|
*
|
||||||
|
* **MiraiExperimentalAPI**: 此 API 可能在将来版本修改
|
||||||
|
*/
|
||||||
|
@SinceMirai("0.34.0")
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
interface ConstrainSingle<M : Message> : MessageMetadata {
|
||||||
|
val key: Message.Key<M>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
interface MessageContent : SingleMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 [this] 发送给指定联系人
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
suspend inline fun <C : Contact> MessageChain.sendTo(contact: C): 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 {
|
when {
|
||||||
this is SingleMessage && tail is SingleMessage -> {
|
this is SingleMessage && tail is SingleMessage -> {
|
||||||
if (this is ConstrainSingle<*> && tail is ConstrainSingle<*>) {
|
if (this is ConstrainSingle<*> && tail is ConstrainSingle<*>) {
|
||||||
@ -167,197 +375,3 @@ interface Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到包含 mirai 消息元素代码的, 易读的字符串. 如 `At(member) + "test"` 将转为 `"[mirai:at:qqId]test"`
|
|
||||||
*
|
|
||||||
* 各个 [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]: 直接无间隔地连接所有元素.
|
|
||||||
*
|
|
||||||
* @see contentToString
|
|
||||||
*/
|
|
||||||
override fun toString(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转为最接近官方格式的字符串. 如 `At(member) + "test"` 将转为 `"@群名片 test"`.
|
|
||||||
* 对于 [NullMessageChain], 这个函数返回空字符串 ""
|
|
||||||
* 对于其他 [MessageChain], 这个函数返回值同 [toString]
|
|
||||||
*/
|
|
||||||
@SinceMirai("0.34.0")
|
|
||||||
fun contentToString(): String
|
|
||||||
|
|
||||||
operator fun plus(another: Message): MessageChain = this.followedBy(another)
|
|
||||||
|
|
||||||
// don't remove! avoid resolution ambiguity between `CharSequence` and `Message`
|
|
||||||
operator fun plus(another: SingleMessage): MessageChain = this.followedBy(another)
|
|
||||||
|
|
||||||
operator fun plus(another: String): MessageChain = this.followedBy(another.toMessage())
|
|
||||||
|
|
||||||
// `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
|
|
||||||
operator fun plus(another: CharSequence): MessageChain = this.followedBy(another.toString().toMessage())
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
// FOR BINARY COMPATIBILITY UNTIL 1.0.0
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
@PlannedRemoval("1.0.0")
|
|
||||||
@JvmSynthetic
|
|
||||||
@Deprecated(
|
|
||||||
"有歧义, 自行使用 contentToString() 比较",
|
|
||||||
ReplaceWith("this.contentToString() == other"),
|
|
||||||
DeprecationLevel.HIDDEN
|
|
||||||
)
|
|
||||||
infix fun eq(other: Message): Boolean = this.toString() == other.toString()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 [contentToString] 与 [other] 比较
|
|
||||||
*/
|
|
||||||
@PlannedRemoval("1.0.0")
|
|
||||||
@JvmSynthetic
|
|
||||||
@Deprecated(
|
|
||||||
"有歧义, 自行使用 contentToString() 比较",
|
|
||||||
ReplaceWith("this.contentToString() == other"),
|
|
||||||
DeprecationLevel.HIDDEN
|
|
||||||
)
|
|
||||||
infix fun eq(other: String): Boolean = this.contentToString() == other
|
|
||||||
|
|
||||||
@PlannedRemoval("1.0.0")
|
|
||||||
@JvmSynthetic
|
|
||||||
@Deprecated(
|
|
||||||
"有歧义, 自行使用 contentToString() 比较",
|
|
||||||
ReplaceWith("this.contentToString() == other"),
|
|
||||||
DeprecationLevel.HIDDEN
|
|
||||||
)
|
|
||||||
operator fun contains(sub: String): Boolean = false
|
|
||||||
|
|
||||||
@PlannedRemoval("1.0.0")
|
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
|
||||||
@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")
|
|
||||||
@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")
|
|
||||||
@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")
|
|
||||||
@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")
|
|
||||||
@JvmName("plus")
|
|
||||||
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
|
|
||||||
@JvmSynthetic
|
|
||||||
fun plus1(another: CharSequence): CombinedMessage =
|
|
||||||
this.followedByInternalForBinaryCompatibility(another.toString().toMessage())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@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> {
|
|
||||||
return contact.sendMessage(this) as MessageReceipt<C>
|
|
||||||
}
|
|
||||||
|
|
||||||
// inline: for future removal
|
|
||||||
inline fun Message.repeat(count: Int): MessageChain {
|
|
||||||
if (this is ConstrainSingle<*>) {
|
|
||||||
// fast-path
|
|
||||||
return SingleMessageChainImpl(this)
|
|
||||||
}
|
|
||||||
return buildMessageChain(count) {
|
|
||||||
add(this@repeat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmSynthetic
|
|
||||||
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()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较两个消息的 [contentToString]
|
|
||||||
*/
|
|
||||||
override infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 [contentToString] 与 [other] 比较
|
|
||||||
*/
|
|
||||||
override infix fun eq(other: String): Boolean = this.contentToString() == other
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息元数据, 即不含内容的元素.
|
|
||||||
* 包括: [MessageSource]
|
|
||||||
*/
|
|
||||||
interface MessageMetadata : SingleMessage {
|
|
||||||
override val length: Int get() = 0
|
|
||||||
override fun get(index: Int): Char = ""[index] // produce uniform exception
|
|
||||||
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = "".subSequence(startIndex, endIndex)
|
|
||||||
override fun compareTo(other: String): Int = "".compareTo(other)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 约束一个 [MessageChain] 中只存在这一种类型的元素. 新元素将会替换旧元素, 保持原顺序.
|
|
||||||
*
|
|
||||||
* **MiraiExperimentalAPI**: 此 API 可能在将来版本修改
|
|
||||||
*/
|
|
||||||
@SinceMirai("0.34.0")
|
|
||||||
@MiraiExperimentalAPI
|
|
||||||
interface ConstrainSingle<M : Message> : MessageMetadata {
|
|
||||||
val key: Message.Key<M>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息内容
|
|
||||||
*/
|
|
||||||
interface MessageContent : SingleMessage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 [this] 发送给指定联系人
|
|
||||||
*/
|
|
||||||
@JvmSynthetic
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
suspend inline fun <C : Contact> MessageChain.sendTo(contact: C): MessageReceipt<C> =
|
|
||||||
contact.sendMessage(this) as MessageReceipt<C>
|
|
@ -43,10 +43,10 @@ interface MessageChain : Message, Iterable<SingleMessage> {
|
|||||||
@PlannedRemoval("1.0.0")
|
@PlannedRemoval("1.0.0")
|
||||||
@Deprecated(
|
@Deprecated(
|
||||||
"有歧义, 自行使用 contentToString() 比较",
|
"有歧义, 自行使用 contentToString() 比较",
|
||||||
ReplaceWith("this.contentToString() == other"),
|
level = DeprecationLevel.ERROR,
|
||||||
DeprecationLevel.HIDDEN
|
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] 不参加计数.
|
* 元素数量. [EmptyMessageChain] 不参加计数.
|
||||||
@ -289,17 +289,6 @@ fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
inline fun MessageChain.asMessageChain(): MessageChain = this // 避免套娃
|
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]
|
* 将 [this] [扁平化后][flatten] 委托为一个 [MessageChain]
|
||||||
*/
|
*/
|
||||||
@ -390,19 +379,11 @@ fun Message.flatten(): Sequence<SingleMessage> {
|
|||||||
@OptIn(MiraiInternalAPI::class)
|
@OptIn(MiraiInternalAPI::class)
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is MessageChain -> this.asSequence()
|
is MessageChain -> this.asSequence()
|
||||||
is CombinedMessage -> this.flatten() // already constrained single.
|
is CombinedMessage -> this.asSequence() // already constrained single.
|
||||||
else -> sequenceOf(this as SingleMessage)
|
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
|
@JvmSynthetic // make Java user happier with less methods
|
||||||
inline fun MessageChain.flatten(): Sequence<SingleMessage> = this.asSequence() // fast path
|
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> {
|
object EmptyMessageChain : MessageChain, Iterator<SingleMessage> {
|
||||||
override fun contains(sub: String): Boolean = sub.isEmpty()
|
|
||||||
override val size: Int get() = 0
|
override val size: Int get() = 0
|
||||||
override fun toString(): String = ""
|
override fun toString(): String = ""
|
||||||
override fun contentToString(): String = ""
|
override fun contentToString(): String = ""
|
||||||
@ -434,7 +415,6 @@ object NullMessageChain : MessageChain {
|
|||||||
override fun contentToString(): String = ""
|
override fun contentToString(): String = ""
|
||||||
override val size: Int get() = 0
|
override val size: Int get() = 0
|
||||||
override fun equals(other: Any?): Boolean = other === this
|
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")
|
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 }
|
get() = field ?: this.delegate.joinToString("") { it.contentToString() }.also { field = it }
|
||||||
|
|
||||||
override fun contentToString(): String = contentToStringTemp!!
|
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 }
|
get() = field ?: this.joinToString("") { it.contentToString() }.also { field = it }
|
||||||
|
|
||||||
override fun contentToString(): String = contentToStringTemp!!
|
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 toString(): String = this.delegate.toString()
|
||||||
override fun contentToString(): String = this.delegate.contentToString()
|
override fun contentToString(): String = this.delegate.contentToString()
|
||||||
override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
|
override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
|
||||||
override operator fun contains(sub: String): Boolean = sub in delegate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
Loading…
Reference in New Issue
Block a user