Rearrange implementations

This commit is contained in:
Him188 2020-04-13 12:30:37 +08:00
parent a7de970a81
commit 075ed6680f
3 changed files with 270 additions and 254 deletions

View File

@ -285,93 +285,4 @@ interface MessageContent : SingleMessage
@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 {
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
}
)
}
}
}
contact.sendMessage(this) as MessageReceipt<C>

View File

@ -246,7 +246,7 @@ fun Collection<SingleMessage>.asMessageChain(): MessageChain =
*/
@JvmName("newChain")
// @JsName("newChain")
inline fun Collection<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
fun Collection<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 直接将 [this] 委托为一个 [MessageChain]
@ -256,27 +256,27 @@ fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
MessageChainImplByCollection(this.constrainSingleMessages())
@JvmSynthetic
inline fun MessageChain.asMessageChain(): MessageChain = this // 避免套娃
fun MessageChain.asMessageChain(): MessageChain = this // 避免套娃
/**
* [this] [扁平化后][flatten] 委托为一个 [MessageChain]
*/
@JvmName("newChain")
// @JsName("newChain")
inline fun Iterable<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
fun Iterable<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 直接将 [this] 委托为一个 [MessageChain]
*/
@JvmSynthetic
inline fun Sequence<SingleMessage>.asMessageChain(): MessageChain = MessageChainImplBySequence(this)
fun Sequence<SingleMessage>.asMessageChain(): MessageChain = MessageChainImplBySequence(this)
/**
* [this] [扁平化后][flatten] 委托为一个 [MessageChain]
*/
@JvmName("newChain")
// @JsName("newChain")
inline fun Sequence<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
fun Sequence<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 构造一个 [MessageChain]
@ -386,162 +386,3 @@ object NullMessageChain : MessageChain {
override fun equals(other: Any?): Boolean = other === this
override fun iterator(): MutableIterator<SingleMessage> = error("accessing NullMessageChain")
}
////////////////////////////
// region implementations
///////////////////////////
@OptIn(MiraiExperimentalAPI::class)
internal fun Sequence<SingleMessage>.constrainSingleMessages(): List<SingleMessage> {
val iterator = this.iterator()
return constrainSingleMessagesImpl supplier@{
if (iterator.hasNext()) {
iterator.next()
} else null
}
}
@MiraiExperimentalAPI
internal inline fun constrainSingleMessagesImpl(iterator: () -> SingleMessage?): ArrayList<SingleMessage> {
val list = ArrayList<SingleMessage>()
var firstConstrainIndex = -1
var next: SingleMessage?
do {
next = iterator()
next?.let { singleMessage ->
if (singleMessage is ConstrainSingle<*>) {
if (firstConstrainIndex == -1) {
firstConstrainIndex = list.size // we are going to add one
} else {
val key = singleMessage.key
val index = list.indexOfFirst(firstConstrainIndex) { it is ConstrainSingle<*> && it.key == key }
if (index != -1) {
list[index] = singleMessage
return@let
}
}
}
list.add(singleMessage)
} ?: return list
} while (true)
}
@OptIn(MiraiExperimentalAPI::class)
internal fun Iterable<SingleMessage>.constrainSingleMessages(): List<SingleMessage> {
val iterator = this.iterator()
return constrainSingleMessagesImpl supplier@{
if (iterator.hasNext()) {
iterator.next()
} else null
}
}
internal inline fun <T> List<T>.indexOfFirst(offset: Int, predicate: (T) -> Boolean): Int {
for (index in offset..this.lastIndex) {
if (predicate(this[index]))
return index
}
return -1
}
@OptIn(MiraiExperimentalAPI::class)
@JvmSynthetic
@Suppress("UNCHECKED_CAST")
internal fun <M : Message> MessageChain.firstOrNullImpl(key: Message.Key<M>): M? = when (key) {
At -> firstIsInstanceOrNull<At>()
AtAll -> firstIsInstanceOrNull<AtAll>()
PlainText -> firstIsInstanceOrNull<PlainText>()
Image -> firstIsInstanceOrNull<Image>()
OnlineImage -> firstIsInstanceOrNull<OnlineImage>()
OfflineImage -> firstIsInstanceOrNull<OfflineImage>()
GroupImage -> firstIsInstanceOrNull<GroupImage>()
FriendImage -> firstIsInstanceOrNull<FriendImage>()
Face -> firstIsInstanceOrNull<Face>()
QuoteReply -> firstIsInstanceOrNull<QuoteReply>()
MessageSource -> firstIsInstanceOrNull<MessageSource>()
OnlineMessageSource -> firstIsInstanceOrNull<OnlineMessageSource>()
OfflineMessageSource -> firstIsInstanceOrNull<OfflineMessageSource>()
OnlineMessageSource.Outgoing -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing>()
OnlineMessageSource.Outgoing.ToGroup -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing.ToGroup>()
OnlineMessageSource.Outgoing.ToFriend -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing.ToFriend>()
OnlineMessageSource.Incoming -> firstIsInstanceOrNull<OnlineMessageSource.Incoming>()
OnlineMessageSource.Incoming.FromGroup -> firstIsInstanceOrNull<OnlineMessageSource.Incoming.FromGroup>()
OnlineMessageSource.Incoming.FromFriend -> firstIsInstanceOrNull<OnlineMessageSource.Incoming.FromFriend>()
OnlineMessageSource -> firstIsInstanceOrNull<OnlineMessageSource>()
XmlMessage -> firstIsInstanceOrNull<XmlMessage>()
JsonMessage -> firstIsInstanceOrNull<JsonMessage>()
RichMessage -> firstIsInstanceOrNull<RichMessage>()
LightApp -> firstIsInstanceOrNull<LightApp>()
PokeMessage -> firstIsInstanceOrNull<PokeMessage>()
HummerMessage -> firstIsInstanceOrNull<HummerMessage>()
FlashImage -> firstIsInstanceOrNull<FlashImage>()
GroupFlashImage -> firstIsInstanceOrNull<GroupFlashImage>()
FriendFlashImage -> firstIsInstanceOrNull<FriendFlashImage>()
else -> null
} as M?
/**
* 使用 [Collection] 作为委托的 [MessageChain]
*/
@PublishedApi
internal class MessageChainImplByCollection constructor(
internal val delegate: Collection<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable
) : Message, Iterable<SingleMessage>, MessageChain {
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 }
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!!
}
/**
* 使用 [Iterable] 作为委托的 [MessageChain]
*/
@PublishedApi
internal class MessageChainImplBySequence constructor(
delegate: Sequence<SingleMessage> // 可以有重复 ConstrainSingle
) : Message, Iterable<SingleMessage>, MessageChain {
override val size: Int by lazy { collected.size }
/**
* [Sequence] 可能只能消耗一遍, 因此需要先转为 [List]
*/
private val collected: List<SingleMessage> by lazy { delegate.constrainSingleMessages() }
override fun iterator(): Iterator<SingleMessage> = collected.iterator()
private var toStringTemp: String? = null
get() = field ?: this.joinToString("") { it.toString() }.also { field = it }
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]
*/
@PublishedApi
internal class SingleMessageChainImpl constructor(
internal val delegate: SingleMessage
) : Message, Iterable<SingleMessage>, MessageChain {
override val size: Int get() = 1
override fun toString(): String = this.delegate.toString()
override fun contentToString(): String = this.delegate.contentToString()
override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
}
// endregion

View File

@ -0,0 +1,264 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/////////////////////////
//// 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))
}
@JvmSynthetic
internal 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
}
)
}
}
}
@OptIn(MiraiExperimentalAPI::class)
@JvmSynthetic
internal fun Sequence<SingleMessage>.constrainSingleMessages(): List<SingleMessage> {
val iterator = this.iterator()
return constrainSingleMessagesImpl supplier@{
if (iterator.hasNext()) {
iterator.next()
} else null
}
}
@MiraiExperimentalAPI
@JvmSynthetic
internal inline fun constrainSingleMessagesImpl(iterator: () -> SingleMessage?): ArrayList<SingleMessage> {
val list = ArrayList<SingleMessage>()
var firstConstrainIndex = -1
var next: SingleMessage?
do {
next = iterator()
next?.let { singleMessage ->
if (singleMessage is ConstrainSingle<*>) {
if (firstConstrainIndex == -1) {
firstConstrainIndex = list.size // we are going to add one
} else {
val key = singleMessage.key
val index = list.indexOfFirst(firstConstrainIndex) { it is ConstrainSingle<*> && it.key == key }
if (index != -1) {
list[index] = singleMessage
return@let
}
}
}
list.add(singleMessage)
} ?: return list
} while (true)
}
@JvmSynthetic
@OptIn(MiraiExperimentalAPI::class)
internal fun Iterable<SingleMessage>.constrainSingleMessages(): List<SingleMessage> {
val iterator = this.iterator()
return constrainSingleMessagesImpl supplier@{
if (iterator.hasNext()) {
iterator.next()
} else null
}
}
@JvmSynthetic
internal inline fun <T> List<T>.indexOfFirst(offset: Int, predicate: (T) -> Boolean): Int {
for (index in offset..this.lastIndex) {
if (predicate(this[index]))
return index
}
return -1
}
@OptIn(MiraiExperimentalAPI::class)
@JvmSynthetic
@Suppress("UNCHECKED_CAST")
internal fun <M : Message> MessageChain.firstOrNullImpl(key: Message.Key<M>): M? = when (key) {
At -> firstIsInstanceOrNull<At>()
AtAll -> firstIsInstanceOrNull<AtAll>()
PlainText -> firstIsInstanceOrNull<PlainText>()
Image -> firstIsInstanceOrNull<Image>()
OnlineImage -> firstIsInstanceOrNull<OnlineImage>()
OfflineImage -> firstIsInstanceOrNull<OfflineImage>()
GroupImage -> firstIsInstanceOrNull<GroupImage>()
FriendImage -> firstIsInstanceOrNull<FriendImage>()
Face -> firstIsInstanceOrNull<Face>()
QuoteReply -> firstIsInstanceOrNull<QuoteReply>()
MessageSource -> firstIsInstanceOrNull<MessageSource>()
OnlineMessageSource -> firstIsInstanceOrNull<OnlineMessageSource>()
OfflineMessageSource -> firstIsInstanceOrNull<OfflineMessageSource>()
OnlineMessageSource.Outgoing -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing>()
OnlineMessageSource.Outgoing.ToGroup -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing.ToGroup>()
OnlineMessageSource.Outgoing.ToFriend -> firstIsInstanceOrNull<OnlineMessageSource.Outgoing.ToFriend>()
OnlineMessageSource.Incoming -> firstIsInstanceOrNull<OnlineMessageSource.Incoming>()
OnlineMessageSource.Incoming.FromGroup -> firstIsInstanceOrNull<OnlineMessageSource.Incoming.FromGroup>()
OnlineMessageSource.Incoming.FromFriend -> firstIsInstanceOrNull<OnlineMessageSource.Incoming.FromFriend>()
OnlineMessageSource -> firstIsInstanceOrNull<OnlineMessageSource>()
XmlMessage -> firstIsInstanceOrNull<XmlMessage>()
JsonMessage -> firstIsInstanceOrNull<JsonMessage>()
RichMessage -> firstIsInstanceOrNull<RichMessage>()
LightApp -> firstIsInstanceOrNull<LightApp>()
PokeMessage -> firstIsInstanceOrNull<PokeMessage>()
HummerMessage -> firstIsInstanceOrNull<HummerMessage>()
FlashImage -> firstIsInstanceOrNull<FlashImage>()
GroupFlashImage -> firstIsInstanceOrNull<GroupFlashImage>()
FriendFlashImage -> firstIsInstanceOrNull<FriendFlashImage>()
else -> null
} as M?
/**
* 使用 [Collection] 作为委托的 [MessageChain]
*/
internal class MessageChainImplByCollection constructor(
internal val delegate: Collection<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable
) : Message, Iterable<SingleMessage>, MessageChain {
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 }
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!!
}
/**
* 使用 [Iterable] 作为委托的 [MessageChain]
*/
internal class MessageChainImplBySequence constructor(
delegate: Sequence<SingleMessage> // 可以有重复 ConstrainSingle
) : Message, Iterable<SingleMessage>, MessageChain {
override val size: Int by lazy { collected.size }
/**
* [Sequence] 可能只能消耗一遍, 因此需要先转为 [List]
*/
private val collected: List<SingleMessage> by lazy { delegate.constrainSingleMessages() }
override fun iterator(): Iterator<SingleMessage> = collected.iterator()
private var toStringTemp: String? = null
get() = field ?: this.joinToString("") { it.toString() }.also { field = it }
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, Iterable<SingleMessage>, MessageChain {
override val size: Int get() = 1
override fun toString(): String = this.delegate.toString()
override fun contentToString(): String = this.delegate.contentToString()
override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
}