Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
b8b749bf
Commit
b8b749bf
authored
Apr 06, 2020
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Completed CombinedMessage redesigning and constraining on concatenation
parent
eaa1e96a
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
494 additions
and
282 deletions
+494
-282
compatibility-validator/build.gradle.kts
compatibility-validator/build.gradle.kts
+18
-1
compatibility-validator/src/main/kotlin/compatibility/testKotlinCompatibility.kt
.../src/main/kotlin/compatibility/testKotlinCompatibility.kt
+14
-0
compatibility-validator/src/test/kotlin/compatibility/CombinedMessageTest.kt
...ator/src/test/kotlin/compatibility/CombinedMessageTest.kt
+79
-0
compatibility-validator/src/test/kotlin/compatibility/TestKotlinCompatibility.kt
.../src/test/kotlin/compatibility/TestKotlinCompatibility.kt
+27
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
...n/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
+4
-2
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
...onMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
...moe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+2
-2
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
...e/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+1
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
...monMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
+2
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
...ommonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+8
-8
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
.../src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
+3
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
+3
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt
...in/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt
+52
-46
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
...commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
+143
-48
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
...nMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+65
-57
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
...mmonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
+0
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
...mmonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
+0
-24
mirai-core/src/commonTest/kotlin/net/mamoe/mirai/message.data/CombinedMessageTest.kt
...otlin/net/mamoe/mirai/message.data/CombinedMessageTest.kt
+4
-81
mirai-core/src/commonTest/kotlin/net/mamoe/mirai/message.data/ConstrainSingleTest.kt
...otlin/net/mamoe/mirai/message.data/ConstrainSingleTest.kt
+67
-6
No files found.
compatibility-validator/build.gradle.kts
View file @
b8b749bf
...
@@ -7,6 +7,11 @@ plugins {
...
@@ -7,6 +7,11 @@ plugins {
description
=
"Binary and source compatibility validator for mirai-core and mirai-core-qqandroid"
description
=
"Binary and source compatibility validator for mirai-core and mirai-core-qqandroid"
repositories
{
mavenCentral
()
jcenter
()
}
kotlin
{
kotlin
{
sourceSets
{
sourceSets
{
all
{
all
{
...
@@ -17,7 +22,19 @@ kotlin {
...
@@ -17,7 +22,19 @@ kotlin {
main
{
main
{
dependencies
{
dependencies
{
api
(
kotlin
(
"stdlib"
))
api
(
kotlin
(
"stdlib"
))
api
(
project
(
":mirai-core-qqandroid"
))
runtimeOnly
(
project
(
":mirai-core-qqandroid"
))
compileOnly
(
"net.mamoe:mirai-core-qqandroid-jvm:0.33.0"
)
api
(
kotlinx
(
"coroutines-core"
,
Versions
.
Kotlin
.
coroutines
))
}
}
test
{
dependencies
{
api
(
kotlin
(
"stdlib"
))
api
(
kotlin
(
"test"
))
api
(
kotlin
(
"test-junit"
))
runtimeOnly
(
project
(
":mirai-core-qqandroid"
))
compileOnly
(
"net.mamoe:mirai-core-qqandroid-jvm:0.33.0"
)
api
(
kotlinx
(
"coroutines-core"
,
Versions
.
Kotlin
.
coroutines
))
api
(
kotlinx
(
"coroutines-core"
,
Versions
.
Kotlin
.
coroutines
))
}
}
}
}
...
...
compatibility-validator/src/main/kotlin/compatibility/testKotlinCompatibility.kt
0 → 100644
View file @
b8b749bf
/*
* 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
*/
package
compatibility
fun
main
()
{
}
\ No newline at end of file
compatibility-validator/src/test/kotlin/compatibility/CombinedMessageTest.kt
0 → 100644
View file @
b8b749bf
package
compatibility
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
kotlin.test.Test
import
kotlin.test.assertEquals
@OptIn
(
MiraiInternalAPI
::
class
)
internal
class
CombinedMessageTest
{
@Test
fun
testAsSequence
()
{
var
message
:
Message
=
"Hello "
.
toMessage
()
message
+=
"World"
assertEquals
(
"Hello World"
,
(
message
as
CombinedMessage
).
asSequence
().
joinToString
(
separator
=
""
)
)
}
@Test
fun
testAsSequence2
()
{
var
message
:
Message
=
"Hello "
.
toMessage
()
message
+=
listOf
(
PlainText
(
"W"
),
PlainText
(
"o"
),
PlainText
(
"r"
)
+
PlainText
(
"ld"
)
).
asMessageChain
()
assertEquals
(
"Hello World"
,
(
message
as
CombinedMessage
).
asSequence
().
joinToString
(
separator
=
""
)
)
}
}
fun
<
T
>
Iterator
<
T
>.
joinToString
(
separator
:
CharSequence
=
", "
,
prefix
:
CharSequence
=
""
,
postfix
:
CharSequence
=
""
,
limit
:
Int
=
-
1
,
truncated
:
CharSequence
=
"..."
,
transform
:
((
T
)
->
CharSequence
)?
=
null
):
String
{
return
joinTo
(
StringBuilder
(),
separator
,
prefix
,
postfix
,
limit
,
truncated
,
transform
).
toString
()
}
fun
<
T
,
A
:
Appendable
>
Iterator
<
T
>.
joinTo
(
buffer
:
A
,
separator
:
CharSequence
=
", "
,
prefix
:
CharSequence
=
""
,
postfix
:
CharSequence
=
""
,
limit
:
Int
=
-
1
,
truncated
:
CharSequence
=
"..."
,
transform
:
((
T
)
->
CharSequence
)?
=
null
):
A
{
buffer
.
append
(
prefix
)
var
count
=
0
for
(
element
in
this
)
{
if
(++
count
>
1
)
buffer
.
append
(
separator
)
if
(
limit
<
0
||
count
<=
limit
)
{
buffer
.
appendElement
(
element
,
transform
)
}
else
break
}
if
(
limit
in
0
until
count
)
buffer
.
append
(
truncated
)
buffer
.
append
(
postfix
)
return
buffer
}
internal
fun
<
T
>
Appendable
.
appendElement
(
element
:
T
,
transform
:
((
T
)
->
CharSequence
)?)
{
when
{
transform
!=
null
->
append
(
transform
(
element
))
element
is
CharSequence
?
->
append
(
element
)
element
is
Char
->
append
(
element
)
else
->
append
(
element
.
toString
())
}
}
\ No newline at end of file
compatibility-validator/src/test/kotlin/compatibility/TestKotlinCompatibility.kt
0 → 100644
View file @
b8b749bf
/*
* 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
*/
package
compatibility
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.PlainText
import
org.junit.Test
internal
class
TestKotlinCompatibility
{
@Test
fun
testMessageChain
()
{
val
x
=
PlainText
(
"te"
)
+
PlainText
(
"st"
)
println
(
Message
::
class
.
java
.
declaredMethods
.
joinToString
(
"\n"
))
println
()
println
(
x
::
class
.
java
.
declaredMethods
.
joinToString
(
"\n"
))
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
View file @
b8b749bf
...
@@ -56,6 +56,7 @@ import kotlin.coroutines.CoroutineContext
...
@@ -56,6 +56,7 @@ import kotlin.coroutines.CoroutineContext
import
kotlin.jvm.JvmSynthetic
import
kotlin.jvm.JvmSynthetic
import
kotlin.math.absoluteValue
import
kotlin.math.absoluteValue
import
kotlin.random.Random
import
kotlin.random.Random
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo
as
JceFriendInfo
@OptIn
(
ExperimentalContracts
::
class
)
@OptIn
(
ExperimentalContracts
::
class
)
internal
fun
Bot
.
asQQAndroidBot
():
QQAndroidBot
{
internal
fun
Bot
.
asQQAndroidBot
():
QQAndroidBot
{
...
@@ -98,8 +99,9 @@ internal abstract class QQAndroidBotBase constructor(
...
@@ -98,8 +99,9 @@ internal abstract class QQAndroidBotBase constructor(
override
val
friends
:
ContactList
<
QQ
>
=
ContactList
(
LockFreeLinkedList
())
override
val
friends
:
ContactList
<
QQ
>
=
ContactList
(
LockFreeLinkedList
())
override
lateinit
var
nick
:
String
override
val
nick
:
String
get
()
=
selfInfo
.
nick
internal
set
internal
lateinit
var
selfInfo
:
JceFriendInfo
override
val
selfQQ
:
QQ
by
lazy
{
override
val
selfQQ
:
QQ
by
lazy
{
@OptIn
(
LowLevelAPI
::
class
)
@OptIn
(
LowLevelAPI
::
class
)
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
View file @
b8b749bf
...
@@ -51,7 +51,7 @@ import kotlin.jvm.JvmSynthetic
...
@@ -51,7 +51,7 @@ import kotlin.jvm.JvmSynthetic
internal
inline
class
FriendInfoImpl
(
internal
inline
class
FriendInfoImpl
(
private
val
jceFriendInfo
:
net
.
mamoe
.
mirai
.
qqandroid
.
network
.
protocol
.
data
.
jce
.
FriendInfo
private
val
jceFriendInfo
:
net
.
mamoe
.
mirai
.
qqandroid
.
network
.
protocol
.
data
.
jce
.
FriendInfo
)
:
FriendInfo
{
)
:
FriendInfo
{
override
val
nick
:
String
get
()
=
jceFriendInfo
.
nick
?:
""
override
val
nick
:
String
get
()
=
jceFriendInfo
.
nick
override
val
uin
:
Long
get
()
=
jceFriendInfo
.
friendUin
override
val
uin
:
Long
get
()
=
jceFriendInfo
.
friendUin
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
View file @
b8b749bf
...
@@ -223,8 +223,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
...
@@ -223,8 +223,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}
}
// self info
// self info
data
.
selfInfo
?.
apply
{
data
.
selfInfo
?.
run
{
bot
.
nick
=
nick
?:
""
bot
.
selfInfo
=
this
// bot.remark = remark ?: ""
// bot.remark = remark ?: ""
// bot.sex = sex
// bot.sex = sex
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
View file @
b8b749bf
...
@@ -109,7 +109,7 @@ internal class FriendInfo(
...
@@ -109,7 +109,7 @@ internal class FriendInfo(
@JceId
(
11
)
val
sqqOnLineStateV2
:
Byte
?
=
null
,
@JceId
(
11
)
val
sqqOnLineStateV2
:
Byte
?
=
null
,
@JceId
(
12
)
val
sShowName
:
String
?
=
""
,
@JceId
(
12
)
val
sShowName
:
String
?
=
""
,
@JceId
(
13
)
val
isRemark
:
Byte
?
=
null
,
@JceId
(
13
)
val
isRemark
:
Byte
?
=
null
,
@JceId
(
14
)
val
nick
:
String
?
=
""
,
@JceId
(
14
)
val
nick
:
String
=
""
,
@JceId
(
15
)
val
specialFlag
:
Byte
?
=
null
,
@JceId
(
15
)
val
specialFlag
:
Byte
?
=
null
,
@JceId
(
16
)
val
vecIMGroupID
:
ByteArray
?
=
null
,
@JceId
(
16
)
val
vecIMGroupID
:
ByteArray
?
=
null
,
@JceId
(
17
)
val
vecMSFGroupID
:
ByteArray
?
=
null
,
@JceId
(
17
)
val
vecMSFGroupID
:
ByteArray
?
=
null
,
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
b8b749bf
...
@@ -87,6 +87,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
...
@@ -87,6 +87,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
/**
/**
* 昵称
* 昵称
*/
*/
@SinceMirai
(
"0.33.1"
)
abstract
val
nick
:
String
abstract
val
nick
:
String
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
View file @
b8b749bf
...
@@ -24,7 +24,7 @@ import net.mamoe.mirai.message.ContactMessage
...
@@ -24,7 +24,7 @@ import net.mamoe.mirai.message.ContactMessage
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.first
import
net.mamoe.mirai.message.data.first
IsInstance
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.InvocationKind
...
@@ -700,7 +700,7 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>(
...
@@ -700,7 +700,7 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>(
@MessageDsl
@MessageDsl
@SinceMirai
(
"0.30.0"
)
@SinceMirai
(
"0.30.0"
)
inline
fun
<
reified
N
:
Message
>
has
(
noinline
onEvent
:
@MessageDsl
suspend
M
.(
N
)
->
R
):
Ret
=
inline
fun
<
reified
N
:
Message
>
has
(
noinline
onEvent
:
@MessageDsl
suspend
M
.(
N
)
->
R
):
Ret
=
content
({
message
.
any
{
it
is
N
}
},
{
onEvent
.
invoke
(
this
,
message
.
first
())
})
content
({
message
.
any
{
it
is
N
}
},
{
onEvent
.
invoke
(
this
,
message
.
first
IsInstance
())
})
/**
/**
* 如果 [mapper] 返回值非空, 就执行 [onEvent]
* 如果 [mapper] 返回值非空, 就执行 [onEvent]
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
View file @
b8b749bf
...
@@ -357,8 +357,8 @@ suspend inline fun <reified M : Message> ContactMessage.nextMessageContaining(
...
@@ -357,8 +357,8 @@ suspend inline fun <reified M : Message> ContactMessage.nextMessageContaining(
):
M
{
):
M
{
return
subscribingGet
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
return
subscribingGet
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContaining
)
}
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContaining
)
}
.
takeIf
{
this
.
message
.
any
<
M
>()
}
.
takeIf
{
this
.
message
.
any
IsInstance
<
M
>()
}
}.
message
.
first
()
}.
message
.
first
IsInstance
()
}
}
@JvmSynthetic
@JvmSynthetic
...
@@ -370,8 +370,8 @@ inline fun <reified M : Message> ContactMessage.nextMessageContainingAsync(
...
@@ -370,8 +370,8 @@ inline fun <reified M : Message> ContactMessage.nextMessageContainingAsync(
@Suppress
(
"RemoveExplicitTypeArguments"
)
@Suppress
(
"RemoveExplicitTypeArguments"
)
subscribingGet
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
subscribingGet
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingAsync
)
}
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingAsync
)
}
.
takeIf
{
this
.
message
.
any
<
M
>()
}
.
takeIf
{
this
.
message
.
any
IsInstance
<
M
>()
}
}.
message
.
first
<
M
>()
}.
message
.
first
IsInstance
<
M
>()
}
}
}
}
...
@@ -391,8 +391,8 @@ suspend inline fun <reified M : Message> ContactMessage.nextMessageContainingOrN
...
@@ -391,8 +391,8 @@ suspend inline fun <reified M : Message> ContactMessage.nextMessageContainingOrN
):
M
?
{
):
M
?
{
return
subscribingGetOrNull
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
return
subscribingGetOrNull
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingOrNull
)
}
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingOrNull
)
}
.
takeIf
{
this
.
message
.
any
<
M
>()
}
.
takeIf
{
this
.
message
.
any
IsInstance
<
M
>()
}
}
?.
message
?.
first
()
}
?.
message
?.
first
IsInstance
()
}
}
@JvmSynthetic
@JvmSynthetic
...
@@ -403,8 +403,8 @@ inline fun <reified M : Message> ContactMessage.nextMessageContainingOrNullAsync
...
@@ -403,8 +403,8 @@ inline fun <reified M : Message> ContactMessage.nextMessageContainingOrNullAsync
return
this
.
bot
.
async
(
coroutineContext
)
{
return
this
.
bot
.
async
(
coroutineContext
)
{
subscribingGetOrNull
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
subscribingGetOrNull
<
ContactMessage
,
ContactMessage
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingOrNullAsync
)
}
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessageContainingOrNullAsync
)
}
.
takeIf
{
this
.
message
.
any
<
M
>()
}
.
takeIf
{
this
.
message
.
any
IsInstance
<
M
>()
}
}
?.
message
?.
first
<
M
>()
}
?.
message
?.
first
IsInstance
<
M
>()
}
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
View file @
b8b749bf
...
@@ -17,6 +17,7 @@ package net.mamoe.mirai.message.data
...
@@ -17,6 +17,7 @@ package net.mamoe.mirai.message.data
import
net.mamoe.mirai.LowLevelAPI
import
net.mamoe.mirai.LowLevelAPI
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.nameCardOrNick
import
net.mamoe.mirai.contact.nameCardOrNick
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmStatic
import
kotlin.jvm.JvmStatic
...
@@ -56,6 +57,7 @@ private constructor(val target: Long, val display: String) :
...
@@ -56,6 +57,7 @@ private constructor(val target: Long, val display: String) :
}
}
// 自动为消息补充 " "
// 自动为消息补充 " "
@OptIn
(
MiraiInternalAPI
::
class
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@JvmName
(
"followedBy"
)
@JvmName
(
"followedBy"
)
...
@@ -67,7 +69,7 @@ private constructor(val target: Long, val display: String) :
...
@@ -67,7 +69,7 @@ private constructor(val target: Long, val display: String) :
return
followedByInternalForBinaryCompatibility
(
PlainText
(
" "
)
+
tail
)
return
followedByInternalForBinaryCompatibility
(
PlainText
(
" "
)
+
tail
)
}
}
override
fun
followedBy
(
tail
:
Message
):
Message
{
override
fun
followedBy
(
tail
:
Message
):
Message
Chain
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
return
super
.
followedBy
(
tail
)
return
super
.
followedBy
(
tail
)
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
View file @
b8b749bf
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
package
net.mamoe.mirai.message.data
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
...
@@ -42,6 +43,7 @@ object AtAll :
...
@@ -42,6 +43,7 @@ object AtAll :
override
fun
contentToString
():
String
=
display
override
fun
contentToString
():
String
=
display
// 自动为消息补充 " "
// 自动为消息补充 " "
@OptIn
(
MiraiInternalAPI
::
class
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"followedBy"
)
@JvmName
(
"followedBy"
)
...
@@ -53,7 +55,7 @@ object AtAll :
...
@@ -53,7 +55,7 @@ object AtAll :
return
followedByInternalForBinaryCompatibility
(
PlainText
(
" "
)
+
tail
)
return
followedByInternalForBinaryCompatibility
(
PlainText
(
" "
)
+
tail
)
}
}
override
fun
followedBy
(
tail
:
Message
):
Message
{
override
fun
followedBy
(
tail
:
Message
):
Message
Chain
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
return
super
.
followedBy
(
tail
)
return
super
.
followedBy
(
tail
)
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt
View file @
b8b749bf
...
@@ -14,11 +14,13 @@ package net.mamoe.mirai.message.data
...
@@ -14,11 +14,13 @@ 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
/**
/**
*
链接的两个消息
.
*
快速链接的两个消息 (避免构造新的 list)
.
*
*
* 不要直接构造 [CombinedMessage], 使用 [Message.plus]
* 不要直接构造 [CombinedMessage], 使用 [Message.plus]
* 要连接多个 [Message], 使用 [buildMessageChain]
* 要连接多个 [Message], 使用 [buildMessageChain]
...
@@ -27,64 +29,68 @@ import kotlin.jvm.JvmName
...
@@ -27,64 +29,68 @@ import kotlin.jvm.JvmName
*
*
* Left-biased list
* Left-biased list
*/
*/
@MiraiInternalAPI
(
"this API is going to be internal"
)
class
CombinedMessage
class
CombinedMessage
@Deprecated
(
message
=
"use Message.plus"
,
level
=
DeprecationLevel
.
ERROR
)
internal
constructor
(
@MiraiInternalAPI
(
"CombinedMessage 构造器可能会在将来被改动"
)
constructor
(
internal
val
left
:
Message
,
// 必须已经完成 constrain single
@MiraiExperimentalAPI
(
"CombinedMessage.left 可能会在将来被改动"
)
internal
val
tail
:
Message
val
left
:
SingleMessage
,
)
:
Message
,
MessageChain
{
@MiraiExperimentalAPI
(
"CombinedMessage.tail 可能会在将来被改动"
)
val
tail
:
SingleMessage
)
:
Iterable
<
SingleMessage
>,
Message
{
/*
// 不要把它用作 local function, 会编译错误
@OptIn(MiraiExperimentalAPI::class)
private suspend fun SequenceScope<Message>.yieldCombinedOrElements(message: Message) {
when (message) {
is CombinedMessage -> {
// fast path, 避免创建新的 iterator, 也不会挂起协程
yieldCombinedOrElements(message.left)
yieldCombinedOrElements(message.tail)
}
is Iterable<*> -> {
// 更好的性能, 因为协程不会挂起.
// 这可能会导致爆栈 (十万个元素), 但作为消息序列足够了.
message.forEach {
yieldCombinedOrElements(
it as? Message ?: error(
"A Message implementing Iterable must implement Iterable<Message>, " +
"whereas got ${it!!::class.simpleName}"
)
)
}
}
else -> {
check(message is SingleMessage) {
"unsupported Message type. " +
"A Message must be a CombinedMessage, a Iterable<Message> or a SingleMessage"
}
yield(message)
}
}
}
*/
@OptIn
(
MiraiExperimentalAPI
::
class
)
@OptIn
(
MiraiExperimentalAPI
::
class
)
fun
asSequence
():
Sequence
<
SingleMessage
>
=
sequence
{
fun
asSequence
():
Sequence
<
SingleMessage
>
=
sequence
{
yield
(
left
)
yieldCombinedOrElementsFlatten
(
this
@CombinedMessage
)
yield
(
tail
)
}
}
override
fun
iterator
():
Iterator
<
SingleMessage
>
{
override
fun
iterator
():
Iterator
<
SingleMessage
>
{
return
asSequence
().
iterator
()
return
asSequence
().
iterator
()
}
}
@PlannedRemoval
(
"1.0.0"
)
@Deprecated
(
"有歧义, 自行使用 contentToString() 比较"
,
ReplaceWith
(
"this.contentToString() == other"
),
DeprecationLevel
.
HIDDEN
)
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
)
override
fun
toString
():
String
{
override
fun
toString
():
String
{
return
tail
.
toString
()
+
left
.
toString
()
return
tail
.
toString
()
+
left
.
toString
()
}
}
override
fun
contentToString
():
String
{
override
fun
contentToString
():
String
{
return
toString
()
return
left
.
contentToString
()
+
tail
.
contentToString
()
}
}
@JvmSynthetic
// 不要把它用作 local function, 会编译错误
@OptIn
(
MiraiExperimentalAPI
::
class
,
MiraiInternalAPI
::
class
)
private
suspend
fun
SequenceScope
<
SingleMessage
>.
yieldCombinedOrElementsFlatten
(
message
:
Message
)
{
when
(
message
)
{
is
CombinedMessage
->
{
// fast path, 避免创建新的 iterator, 也不会挂起协程
yieldCombinedOrElementsFlatten
(
message
.
left
)
yieldCombinedOrElementsFlatten
(
message
.
tail
)
}
is
MessageChain
->
{
yieldAll
(
message
)
}
else
->
{
check
(
message
is
SingleMessage
)
{
"unsupported Message type: ${message::class}"
+
"A Message must be a CombinedMessage, a Iterable<Message> or a SingleMessage"
}
yield
(
message
)
}
}
}
}
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
View file @
b8b749bf
...
@@ -15,6 +15,7 @@ import net.mamoe.mirai.contact.Contact
...
@@ -15,6 +15,7 @@ import net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.MessageReceipt
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
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmSynthetic
import
kotlin.jvm.JvmSynthetic
...
@@ -24,16 +25,16 @@ import kotlin.jvm.JvmSynthetic
...
@@ -24,16 +25,16 @@ import kotlin.jvm.JvmSynthetic
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
*
*
* [消息][Message] 分为
* [消息][Message] 分为
* - [
MessageMetadata] 消息元数据, 包括: [消息来源][MessageSource]
* - [
SingleMessage]:
*
- [MessageContent] 单个消息, 包括: [纯文本][PlainText], [@群员][At], [@全体成员][AtAll] 等
.
*
- [MessageMetadata] 消息元数据, 包括: [消息来源][MessageSource], [引用回复][QuoteReply]
.
*
- [CombinedMessage] 通过 [plus] 连接的两个消息. 可通过 [asMessageChain] 转换为 [MessageChain]
*
- [MessageContent] 含内容的消息, 包括: [纯文本][PlainText], [@群员][At], [@全体成员][AtAll] 等.
* - [MessageChain] 不可变消息链, 链表形式链接的多个 [SingleMessage] 实例.
* - [MessageChain]
:
不可变消息链, 链表形式链接的多个 [SingleMessage] 实例.
*
*
* #### 在 Kotlin 使用 [Message]:
* #### 在 Kotlin 使用 [Message]:
* 这与使用 [String] 的使用非常类似.
* 这与使用 [String] 的使用非常类似.
*
*
* 比较 [
Message] 与 [String] (使用 infix [Message.eq])
:
* 比较 [
SingleMessage] 与 [String]
:
* `if(
event eq
"你好") qq.sendMessage(event)`
* `if(
message.contentToString() ==
"你好") qq.sendMessage(event)`
*
*
* 连接 [Message] 与 [Message], [String], (使用 operator [Message.plus]):
* 连接 [Message] 与 [Message], [String], (使用 operator [Message.plus]):
* ```kotlin
* ```kotlin
...
@@ -65,6 +66,7 @@ import kotlin.jvm.JvmSynthetic
...
@@ -65,6 +66,7 @@ import kotlin.jvm.JvmSynthetic
*
*
* @see Contact.sendMessage 发送消息
* @see Contact.sendMessage 发送消息
*/
*/
@OptIn
(
MiraiInternalAPI
::
class
)
interface
Message
{
interface
Message
{
/**
/**
* 类型 Key.
* 类型 Key.
...
@@ -75,25 +77,16 @@ interface Message {
...
@@ -75,25 +77,16 @@ interface Message {
*/
*/
interface
Key
<
out
M
:
Message
>
{
interface
Key
<
out
M
:
Message
>
{
/**
/**
* 此 [Key] 指代的 [Message] 类型名. 一般为 `class.simpleName`
* 此 [Key] 指代的 [Message] 类型名. 一般为 `class.simpleName`
, 如 "QuoteReply", "PlainText"
*/
*/
@SinceMirai
(
"0.34.0"
)
@SinceMirai
(
"0.34.0"
)
val
typeName
:
String
val
typeName
:
String
}
}
infix
fun
eq
(
other
:
Message
):
Boolean
=
this
.
toString
()
==
other
.
toString
()
/**
* 将 [toString] 与 [other] 比较
*/
infix
fun
eq
(
other
:
String
):
Boolean
=
this
.
toString
()
==
other
operator
fun
contains
(
sub
:
String
):
Boolean
=
false
/**
/**
* 把 `this` 连接到 [tail] 的头部. 类似于字符串相加.
* 把 `this` 连接到 [tail] 的头部. 类似于字符串相加.
*
*
* 连接后
无法保证 [ConstrainSingle] 的元素单独存在. 需在
* 连接后
可以保证 [ConstrainSingle] 的元素单独存在.
*
*
* 例:
* 例:
* ```kotlin
* ```kotlin
...
@@ -111,17 +104,67 @@ interface Message {
...
@@ -111,17 +104,67 @@ 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
):
Message
{
fun
followedBy
(
tail
:
Message
):
Message
Chain
{
TODO
()
when
{
if
(
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
<
*
>)
{
return
if
(
this
.
key
==
tail
.
key
)
{
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
tail
}
else
{
}
else
null
CombinedMessage
(
this
,
tail
)
}
}
)
}
}
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
}
)
}
}
}
}
}
...
@@ -147,43 +190,79 @@ interface Message {
...
@@ -147,43 +190,79 @@ interface Message {
@SinceMirai
(
"0.34.0"
)
@SinceMirai
(
"0.34.0"
)
fun
contentToString
():
String
fun
contentToString
():
String
operator
fun
plus
(
another
:
Message
):
Message
=
this
.
followedBy
(
another
)
operator
fun
plus
(
another
:
Message
):
Message
Chain
=
this
.
followedBy
(
another
)
//
avoid resolution ambiguity
//
don't remove! avoid resolution ambiguity between `CharSequence` and `Message`
operator
fun
plus
(
another
:
SingleMessage
):
Message
=
this
.
followedBy
(
another
)
operator
fun
plus
(
another
:
SingleMessage
):
Message
Chain
=
this
.
followedBy
(
another
)
operator
fun
plus
(
another
:
String
):
Message
=
this
.
followedBy
(
another
.
toMessage
())
operator
fun
plus
(
another
:
String
):
Message
Chain
=
this
.
followedBy
(
another
.
toMessage
())
// `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
// `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
operator
fun
plus
(
another
:
CharSequence
):
Message
=
this
.
followedBy
(
another
.
toString
().
toMessage
())
operator
fun
plus
(
another
:
CharSequence
):
MessageChain
=
this
.
followedBy
(
another
.
toString
().
toMessage
())
//////////////////////////////////////
// FOR BINARY COMPATIBILITY UNTIL 1.0.0
// 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"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"followedBy"
)
@JvmName
(
"followedBy"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@JvmSynthetic
@JvmSynthetic
fun
followedBy1
(
tail
:
Message
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
tail
)
fun
followedBy1
(
tail
:
Message
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
tail
)
@PlannedRemoval
(
"1.0.0"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"plus"
)
@JvmName
(
"plus"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@JvmSynthetic
@JvmSynthetic
fun
plus1
(
another
:
Message
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
)
fun
plus1
(
another
:
Message
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
)
@PlannedRemoval
(
"1.0.0"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"plus"
)
@JvmName
(
"plus"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@JvmSynthetic
@JvmSynthetic
fun
plus1
(
another
:
SingleMessage
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
)
fun
plus1
(
another
:
SingleMessage
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
)
@PlannedRemoval
(
"1.0.0"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"plus"
)
@JvmName
(
"plus"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@JvmSynthetic
@JvmSynthetic
fun
plus1
(
another
:
String
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
.
toMessage
())
fun
plus1
(
another
:
String
):
CombinedMessage
=
this
.
followedByInternalForBinaryCompatibility
(
another
.
toMessage
())
@PlannedRemoval
(
"1.0.0"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@Suppress
(
"INAPPLICABLE_JVM_NAME"
)
@JvmName
(
"plus"
)
@JvmName
(
"plus"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -192,24 +271,24 @@ interface Message {
...
@@ -192,24 +271,24 @@ interface Message {
this
.
followedByInternalForBinaryCompatibility
(
another
.
toString
().
toMessage
())
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
)
@OptIn
(
MiraiInternalAPI
::
class
)
@JvmSynthetic
@JvmSynthetic
@Suppress
(
"DEPRECATION_ERROR"
)
@Suppress
(
"DEPRECATION_ERROR"
)
internal
fun
Message
.
followedByInternalForBinaryCompatibility
(
tail
:
Message
):
CombinedMessage
{
internal
fun
Message
.
followedByInternalForBinaryCompatibility
(
tail
:
Message
):
CombinedMessage
{
TODO
()
return
CombinedMessage
(
EmptyMessageChain
,
this
.
followedBy
(
tail
))
if
(
this
is
ConstrainSingle
<
*
>)
{
}
if
(
this
is
SingleMessage
&&
tail
is
SingleMessage
)
{
if
(
this
is
ConstrainSingle
<
*
>
&&
tail
is
ConstrainSingle
<
*
>
&&
this
.
key
==
tail
.
key
)
return
CombinedMessage
(
EmptyMessageChain
,
tail
)
return
CombinedMessage
(
left
=
this
,
tail
=
tail
)
}
else
{
// return CombinedMessage(left = this.constrain)
}
}
}
@JvmSynthetic
@JvmSynthetic
...
@@ -218,7 +297,8 @@ suspend inline fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> {
...
@@ -218,7 +297,8 @@ suspend inline fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> {
return
contact
.
sendMessage
(
this
)
as
MessageReceipt
<
C
>
return
contact
.
sendMessage
(
this
)
as
MessageReceipt
<
C
>
}
}
fun
Message
.
repeat
(
count
:
Int
):
MessageChain
{
// inline: for future removal
inline
fun
Message
.
repeat
(
count
:
Int
):
MessageChain
{
if
(
this
is
ConstrainSingle
<
*
>)
{
if
(
this
is
ConstrainSingle
<
*
>)
{
// fast-path
// fast-path
return
SingleMessageChainImpl
(
this
)
return
SingleMessageChainImpl
(
this
)
...
@@ -231,7 +311,21 @@ fun Message.repeat(count: Int): MessageChain {
...
@@ -231,7 +311,21 @@ fun Message.repeat(count: Int): MessageChain {
@JvmSynthetic
@JvmSynthetic
inline
operator
fun
Message
.
times
(
count
:
Int
):
MessageChain
=
this
.
repeat
(
count
)
inline
operator
fun
Message
.
times
(
count
:
Int
):
MessageChain
=
this
.
repeat
(
count
)
interface
SingleMessage
:
Message
,
CharSequence
,
Comparable
<
String
>
@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
}
/**
/**
* 消息元数据, 即不含内容的元素.
* 消息元数据, 即不含内容的元素.
...
@@ -251,7 +345,7 @@ interface MessageMetadata : SingleMessage {
...
@@ -251,7 +345,7 @@ interface MessageMetadata : SingleMessage {
*/
*/
@SinceMirai
(
"0.34.0"
)
@SinceMirai
(
"0.34.0"
)
@MiraiExperimentalAPI
@MiraiExperimentalAPI
interface
ConstrainSingle
<
M
:
Message
>
:
SingleMessage
{
interface
ConstrainSingle
<
M
:
Message
>
:
MessageMetadata
{
val
key
:
Message
.
Key
<
M
>
val
key
:
Message
.
Key
<
M
>
}
}
...
@@ -263,6 +357,7 @@ interface MessageContent : SingleMessage
...
@@ -263,6 +357,7 @@ interface MessageContent : SingleMessage
/**
/**
* 将 [this] 发送给指定联系人
* 将 [this] 发送给指定联系人
*/
*/
@JvmSynthetic
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
suspend
inline
fun
<
C
:
Contact
>
MessageChain
.
sendTo
(
contact
:
C
):
MessageReceipt
<
C
>
=
suspend
inline
fun
<
C
:
Contact
>
MessageChain
.
sendTo
(
contact
:
C
):
MessageReceipt
<
C
>
=
contact
.
sendMessage
(
this
)
as
MessageReceipt
<
C
>
contact
.
sendMessage
(
this
)
as
MessageReceipt
<
C
>
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
View file @
b8b749bf
...
@@ -40,10 +40,16 @@ import kotlin.reflect.KProperty
...
@@ -40,10 +40,16 @@ import kotlin.reflect.KProperty
* @see flatten 扁平化
* @see flatten 扁平化
*/
*/
interface
MessageChain
:
Message
,
Iterable
<
SingleMessage
>
{
interface
MessageChain
:
Message
,
Iterable
<
SingleMessage
>
{
@PlannedRemoval
(
"1.0.0"
)
@Deprecated
(
"有歧义, 自行使用 contentToString() 比较"
,
ReplaceWith
(
"this.contentToString() == other"
),
DeprecationLevel
.
HIDDEN
)
override
operator
fun
contains
(
sub
:
String
):
Boolean
override
operator
fun
contains
(
sub
:
String
):
Boolean
/**
/**
* 元素数量
* 元素数量
. [EmptyMessageChain] 不参加计数.
*/
*/
@SinceMirai
(
"0.31.1"
)
@SinceMirai
(
"0.31.1"
)
val
size
:
Int
val
size
:
Int
...
@@ -104,20 +110,20 @@ inline fun MessageChain.foreachContent(block: (Message) -> Unit) {
...
@@ -104,20 +110,20 @@ inline fun MessageChain.foreachContent(block: (Message) -> Unit) {
* 获取第一个 [M] 类型的 [Message] 实例
* 获取第一个 [M] 类型的 [Message] 实例
*/
*/
@JvmSynthetic
@JvmSynthetic
inline
fun
<
reified
M
:
Message
?
>
MessageChain
.
firstOrNull
():
M
?
=
this
.
firstOrNull
{
it
is
M
}
as
M
?
inline
fun
<
reified
M
:
Message
?
>
MessageChain
.
first
IsInstance
OrNull
():
M
?
=
this
.
firstOrNull
{
it
is
M
}
as
M
?
/**
/**
* 获取第一个 [M] 类型的 [Message] 实例
* 获取第一个 [M] 类型的 [Message] 实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
*/
@JvmSynthetic
@JvmSynthetic
inline
fun
<
reified
M
:
Message
>
MessageChain
.
first
():
M
=
this
.
first
{
it
is
M
}
as
M
inline
fun
<
reified
M
:
Message
>
MessageChain
.
first
IsInstance
():
M
=
this
.
first
{
it
is
M
}
as
M
/**
/**
* 获取第一个 [M] 类型的 [Message] 实例
* 获取第一个 [M] 类型的 [Message] 实例
*/
*/
@JvmSynthetic
@JvmSynthetic
inline
fun
<
reified
M
:
Message
>
MessageChain
.
any
():
Boolean
=
this
.
any
{
it
is
M
}
inline
fun
<
reified
M
:
Message
>
MessageChain
.
any
IsInstance
():
Boolean
=
this
.
any
{
it
is
M
}
/**
/**
...
@@ -127,35 +133,35 @@ inline fun <reified M : Message> MessageChain.any(): Boolean = this.any { it is
...
@@ -127,35 +133,35 @@ inline fun <reified M : Message> MessageChain.any(): Boolean = this.any { it is
@JvmSynthetic
@JvmSynthetic
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
fun
<
M
:
Message
>
MessageChain
.
firstOrNull
(
key
:
Message
.
Key
<
M
>):
M
?
=
when
(
key
)
{
fun
<
M
:
Message
>
MessageChain
.
firstOrNull
(
key
:
Message
.
Key
<
M
>):
M
?
=
when
(
key
)
{
At
->
firstOrNull
<
At
>()
At
->
first
IsInstance
OrNull
<
At
>()
AtAll
->
firstOrNull
<
AtAll
>()
AtAll
->
first
IsInstance
OrNull
<
AtAll
>()
PlainText
->
firstOrNull
<
PlainText
>()
PlainText
->
first
IsInstance
OrNull
<
PlainText
>()
Image
->
firstOrNull
<
Image
>()
Image
->
first
IsInstance
OrNull
<
Image
>()
OnlineImage
->
firstOrNull
<
OnlineImage
>()
OnlineImage
->
first
IsInstance
OrNull
<
OnlineImage
>()
OfflineImage
->
firstOrNull
<
OfflineImage
>()
OfflineImage
->
first
IsInstance
OrNull
<
OfflineImage
>()
GroupImage
->
firstOrNull
<
GroupImage
>()
GroupImage
->
first
IsInstance
OrNull
<
GroupImage
>()
FriendImage
->
firstOrNull
<
FriendImage
>()
FriendImage
->
first
IsInstance
OrNull
<
FriendImage
>()
Face
->
firstOrNull
<
Face
>()
Face
->
first
IsInstance
OrNull
<
Face
>()
QuoteReply
->
firstOrNull
<
QuoteReply
>()
QuoteReply
->
first
IsInstance
OrNull
<
QuoteReply
>()
MessageSource
->
firstOrNull
<
MessageSource
>()
MessageSource
->
first
IsInstance
OrNull
<
MessageSource
>()
OnlineMessageSource
->
firstOrNull
<
OnlineMessageSource
>()
OnlineMessageSource
->
first
IsInstance
OrNull
<
OnlineMessageSource
>()
OfflineMessageSource
->
firstOrNull
<
OfflineMessageSource
>()
OfflineMessageSource
->
first
IsInstance
OrNull
<
OfflineMessageSource
>()
OnlineMessageSource
.
Outgoing
->
firstOrNull
<
OnlineMessageSource
.
Outgoing
>()
OnlineMessageSource
.
Outgoing
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Outgoing
>()
OnlineMessageSource
.
Outgoing
.
ToGroup
->
firstOrNull
<
OnlineMessageSource
.
Outgoing
.
ToGroup
>()
OnlineMessageSource
.
Outgoing
.
ToGroup
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Outgoing
.
ToGroup
>()
OnlineMessageSource
.
Outgoing
.
ToFriend
->
firstOrNull
<
OnlineMessageSource
.
Outgoing
.
ToFriend
>()
OnlineMessageSource
.
Outgoing
.
ToFriend
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Outgoing
.
ToFriend
>()
OnlineMessageSource
.
Incoming
->
firstOrNull
<
OnlineMessageSource
.
Incoming
>()
OnlineMessageSource
.
Incoming
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Incoming
>()
OnlineMessageSource
.
Incoming
.
FromGroup
->
firstOrNull
<
OnlineMessageSource
.
Incoming
.
FromGroup
>()
OnlineMessageSource
.
Incoming
.
FromGroup
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Incoming
.
FromGroup
>()
OnlineMessageSource
.
Incoming
.
FromFriend
->
firstOrNull
<
OnlineMessageSource
.
Incoming
.
FromFriend
>()
OnlineMessageSource
.
Incoming
.
FromFriend
->
first
IsInstance
OrNull
<
OnlineMessageSource
.
Incoming
.
FromFriend
>()
OnlineMessageSource
->
firstOrNull
<
OnlineMessageSource
>()
OnlineMessageSource
->
first
IsInstance
OrNull
<
OnlineMessageSource
>()
XmlMessage
->
firstOrNull
<
XmlMessage
>()
XmlMessage
->
first
IsInstance
OrNull
<
XmlMessage
>()
JsonMessage
->
firstOrNull
<
JsonMessage
>()
JsonMessage
->
first
IsInstance
OrNull
<
JsonMessage
>()
RichMessage
->
firstOrNull
<
RichMessage
>()
RichMessage
->
first
IsInstance
OrNull
<
RichMessage
>()
LightApp
->
firstOrNull
<
LightApp
>()
LightApp
->
first
IsInstance
OrNull
<
LightApp
>()
PokeMessage
->
firstOrNull
<
PokeMessage
>()
PokeMessage
->
first
IsInstance
OrNull
<
PokeMessage
>()
HummerMessage
->
firstOrNull
<
HummerMessage
>()
HummerMessage
->
first
IsInstance
OrNull
<
HummerMessage
>()
FlashImage
->
firstOrNull
<
FlashImage
>()
FlashImage
->
first
IsInstance
OrNull
<
FlashImage
>()
GroupFlashImage
->
firstOrNull
<
GroupFlashImage
>()
GroupFlashImage
->
first
IsInstance
OrNull
<
GroupFlashImage
>()
FriendFlashImage
->
firstOrNull
<
FriendFlashImage
>()
FriendFlashImage
->
first
IsInstance
OrNull
<
FriendFlashImage
>()
else
->
null
else
->
null
}
as
M
?
}
as
M
?
...
@@ -191,7 +197,8 @@ inline fun <M : Message> MessageChain.any(key: Message.Key<M>): Boolean = firstO
...
@@ -191,7 +197,8 @@ inline fun <M : Message> MessageChain.any(key: Message.Key<M>): Boolean = firstO
* val image: Image by message
* val image: Image by message
*/
*/
@JvmSynthetic
@JvmSynthetic
inline
operator
fun
<
reified
T
:
Message
>
MessageChain
.
getValue
(
thisRef
:
Any
?,
property
:
KProperty
<
*
>):
T
=
this
.
first
()
inline
operator
fun
<
reified
T
:
Message
>
MessageChain
.
getValue
(
thisRef
:
Any
?,
property
:
KProperty
<
*
>):
T
=
this
.
firstIsInstance
()
/**
/**
* 可空的委托
* 可空的委托
...
@@ -215,7 +222,8 @@ inline class OrNullDelegate<out R : Message?>(private val value: Any?) {
...
@@ -215,7 +222,8 @@ inline class OrNullDelegate<out R : Message?>(private val value: Any?) {
* @see orElse 提供一个不存在则使用默认值的委托
* @see orElse 提供一个不存在则使用默认值的委托
*/
*/
@JvmSynthetic
@JvmSynthetic
inline
fun
<
reified
T
:
Message
>
MessageChain
.
orNull
():
OrNullDelegate
<
T
?
>
=
OrNullDelegate
(
this
.
firstOrNull
<
T
>())
inline
fun
<
reified
T
:
Message
>
MessageChain
.
orNull
():
OrNullDelegate
<
T
?
>
=
OrNullDelegate
(
this
.
firstIsInstanceOrNull
<
T
>())
/**
/**
* 提供一个类型的 [Message] 的委托, 若不存在这个类型的 [Message] 则委托会提供 `null`
* 提供一个类型的 [Message] 的委托, 若不存在这个类型的 [Message] 则委托会提供 `null`
...
@@ -234,7 +242,7 @@ inline fun <reified T : Message> MessageChain.orNull(): OrNullDelegate<T?> = OrN
...
@@ -234,7 +242,7 @@ inline fun <reified T : Message> MessageChain.orNull(): OrNullDelegate<T?> = OrN
inline
fun
<
reified
T
:
Message
?
>
MessageChain
.
orElse
(
inline
fun
<
reified
T
:
Message
?
>
MessageChain
.
orElse
(
lazyDefault
:
()
->
T
lazyDefault
:
()
->
T
):
OrNullDelegate
<
T
>
=
):
OrNullDelegate
<
T
>
=
OrNullDelegate
<
T
>(
this
.
firstOrNull
<
T
>()
?:
lazyDefault
())
OrNullDelegate
<
T
>(
this
.
first
IsInstance
OrNull
<
T
>()
?:
lazyDefault
())
// endregion delegate
// endregion delegate
...
@@ -250,6 +258,7 @@ inline fun <reified T : Message?> MessageChain.orElse(
...
@@ -250,6 +258,7 @@ inline fun <reified T : Message?> MessageChain.orElse(
@JvmName
(
"newChain"
)
@JvmName
(
"newChain"
)
@JsName
(
"newChain"
)
@JsName
(
"newChain"
)
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
@OptIn
(
MiraiInternalAPI
::
class
)
fun
Message
.
asMessageChain
():
MessageChain
=
when
(
this
)
{
fun
Message
.
asMessageChain
():
MessageChain
=
when
(
this
)
{
is
MessageChain
->
this
is
MessageChain
->
this
is
CombinedMessage
->
(
this
as
Iterable
<
Message
>).
asMessageChain
()
is
CombinedMessage
->
(
this
as
Iterable
<
Message
>).
asMessageChain
()
...
@@ -281,6 +290,7 @@ fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
...
@@ -281,6 +290,7 @@ fun Iterable<SingleMessage>.asMessageChain(): MessageChain =
inline
fun
MessageChain
.
asMessageChain
():
MessageChain
=
this
// 避免套娃
inline
fun
MessageChain
.
asMessageChain
():
MessageChain
=
this
// 避免套娃
@JvmSynthetic
@JvmSynthetic
@OptIn
(
MiraiInternalAPI
::
class
)
fun
CombinedMessage
.
asMessageChain
():
MessageChain
{
fun
CombinedMessage
.
asMessageChain
():
MessageChain
{
@OptIn
(
MiraiExperimentalAPI
::
class
)
@OptIn
(
MiraiExperimentalAPI
::
class
)
if
(
left
is
SingleMessage
&&
this
.
tail
is
SingleMessage
)
{
if
(
left
is
SingleMessage
&&
this
.
tail
is
SingleMessage
)
{
...
@@ -377,6 +387,7 @@ inline fun Sequence<SingleMessage>.flatten(): Sequence<SingleMessage> = this //
...
@@ -377,6 +387,7 @@ inline fun Sequence<SingleMessage>.flatten(): Sequence<SingleMessage> = this //
* - 其他: 返回 `sequenceOf(this)`
* - 其他: 返回 `sequenceOf(this)`
*/
*/
fun
Message
.
flatten
():
Sequence
<
SingleMessage
>
{
fun
Message
.
flatten
():
Sequence
<
SingleMessage
>
{
@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
.
flatten
()
// already constrained single.
...
@@ -385,6 +396,7 @@ fun Message.flatten(): Sequence<SingleMessage> {
...
@@ -385,6 +396,7 @@ fun Message.flatten(): Sequence<SingleMessage> {
}
}
@JvmSynthetic
// make Java user happier with less methods
@JvmSynthetic
// make Java user happier with less methods
@OptIn
(
MiraiInternalAPI
::
class
)
fun
CombinedMessage
.
flatten
():
Sequence
<
SingleMessage
>
{
fun
CombinedMessage
.
flatten
():
Sequence
<
SingleMessage
>
{
// already constrained single.
// already constrained single.
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
...
@@ -400,17 +412,12 @@ inline fun MessageChain.flatten(): Sequence<SingleMessage> = this.asSequence() /
...
@@ -400,17 +412,12 @@ inline fun MessageChain.flatten(): Sequence<SingleMessage> = this.asSequence() /
/**
/**
* 不含任何元素的 [MessageChain]
* 不含任何元素的 [MessageChain]
*/
*/
object
EmptyMessageChain
:
MessageChain
,
Iterator
<
SingleMessage
>
,
@MiraiExperimentalAPI
SingleMessage
{
object
EmptyMessageChain
:
MessageChain
,
Iterator
<
SingleMessage
>
{
override
fun
contains
(
sub
:
String
):
Boolean
=
sub
.
isEmpty
()
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
=
""
override
val
length
:
Int
get
()
=
0
override
fun
get
(
index
:
Int
):
Char
=
""
[
index
]
override
fun
subSequence
(
startIndex
:
Int
,
endIndex
:
Int
):
CharSequence
=
""
.
subSequence
(
startIndex
,
endIndex
)
override
fun
compareTo
(
other
:
String
):
Int
=
""
.
compareTo
(
other
)
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
this
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
this
override
fun
hasNext
():
Boolean
=
false
override
fun
hasNext
():
Boolean
=
false
override
fun
next
():
SingleMessage
=
throw
NoSuchElementException
(
"EmptyMessageChain is empty."
)
override
fun
next
():
SingleMessage
=
throw
NoSuchElementException
(
"EmptyMessageChain is empty."
)
...
@@ -495,20 +502,21 @@ internal inline fun <T> List<T>.indexOfFirst(offset: Int, predicate: (T) -> Bool
...
@@ -495,20 +502,21 @@ internal inline fun <T> List<T>.indexOfFirst(offset: Int, predicate: (T) -> Bool
*/
*/
@PublishedApi
@PublishedApi
internal
class
MessageChainImplByCollection
constructor
(
internal
class
MessageChainImplByCollection
constructor
(
private
val
delegate
:
Collection
<
SingleMessage
>
// 必须 constrainSingleMessages, 且为 immutable
internal
val
delegate
:
Collection
<
SingleMessage
>
// 必须 constrainSingleMessages, 且为 immutable
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
override
val
size
:
Int
get
()
=
delegate
.
size
override
val
size
:
Int
get
()
=
delegate
.
size
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
delegate
.
iterator
()
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
delegate
.
iterator
()
private
var
toStringTemp
:
String
?
=
null
private
var
toStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
get
()
=
field
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
field
=
it
}
toStringTemp
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
toStringTemp
=
it
}
private
var
contentToStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
toStringTemp
!!
override
fun
contentToString
():
String
=
contentToStringTemp
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
contentToString
()
}.
also
{
contentToStringTemp
=
it
}
private
var
contentToStringTemp
:
String
?
=
null
get
()
=
field
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
contentToString
()
}.
also
{
field
=
it
}
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
delegate
.
any
{
it
.
contains
(
sub
)
}
override
fun
contentToString
():
String
=
contentToStringTemp
!!
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
sub
in
contentToStringTemp
!!
}
}
/**
/**
...
@@ -525,17 +533,17 @@ internal class MessageChainImplBySequence constructor(
...
@@ -525,17 +533,17 @@ internal class MessageChainImplBySequence constructor(
*/
*/
private
val
collected
:
List
<
SingleMessage
>
by
lazy
{
delegate
.
constrainSingleMessages
()
}
private
val
collected
:
List
<
SingleMessage
>
by
lazy
{
delegate
.
constrainSingleMessages
()
}
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
collected
.
iterator
()
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
collected
.
iterator
()
private
var
toStringTemp
:
String
?
=
null
private
var
toStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
get
()
=
field
?:
this
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
field
=
it
}
toStringTemp
?:
this
.
collected
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
toStringTemp
=
it
}
private
var
contentToStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
toStringTemp
!!
override
fun
contentToString
():
String
=
contentToStringTemp
?:
this
.
collected
.
joinToString
(
""
)
{
it
.
contentToString
()
}
.
also
{
contentToStringTemp
=
it
}
private
var
contentToStringTemp
:
String
?
=
null
get
()
=
field
?:
this
.
joinToString
(
""
)
{
it
.
contentToString
()
}.
also
{
field
=
it
}
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
collected
.
any
{
it
.
contains
(
sub
)
}
override
fun
contentToString
():
String
=
contentToStringTemp
!!
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
sub
in
contentToStringTemp
!!
}
}
/**
/**
...
@@ -543,7 +551,7 @@ internal class MessageChainImplBySequence constructor(
...
@@ -543,7 +551,7 @@ internal class MessageChainImplBySequence constructor(
*/
*/
@PublishedApi
@PublishedApi
internal
class
SingleMessageChainImpl
constructor
(
internal
class
SingleMessageChainImpl
constructor
(
private
val
delegate
:
SingleMessage
internal
val
delegate
:
SingleMessage
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
override
val
size
:
Int
get
()
=
1
override
val
size
:
Int
get
()
=
1
override
fun
toString
():
String
=
this
.
delegate
.
toString
()
override
fun
toString
():
String
=
this
.
delegate
.
toString
()
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
View file @
b8b749bf
...
@@ -30,7 +30,6 @@ class PlainText(val stringValue: String) :
...
@@ -30,7 +30,6 @@ class PlainText(val stringValue: String) :
@Suppress
(
"unused"
)
@Suppress
(
"unused"
)
constructor
(
charSequence
:
CharSequence
)
:
this
(
charSequence
.
toString
())
constructor
(
charSequence
:
CharSequence
)
:
this
(
charSequence
.
toString
())
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
sub
in
stringValue
override
fun
toString
():
String
=
stringValue
override
fun
toString
():
String
=
stringValue
override
fun
contentToString
():
String
=
stringValue
override
fun
contentToString
():
String
=
stringValue
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
View file @
b8b749bf
...
@@ -97,30 +97,6 @@ open class BotConfiguration {
...
@@ -97,30 +97,6 @@ open class BotConfiguration {
fun
fileBasedDeviceInfo
(
filename
:
String
=
"device.json"
)
{
fun
fileBasedDeviceInfo
(
filename
:
String
=
"device.json"
)
{
deviceInfo
=
getFileBasedDeviceInfoSupplier
(
filename
)
deviceInfo
=
getFileBasedDeviceInfoSupplier
(
filename
)
}
}
@PlannedRemoval
(
"0.34.0"
)
@Deprecated
(
"use fileBasedDeviceInfo(filepath"
,
level
=
DeprecationLevel
.
ERROR
,
replaceWith
=
ReplaceWith
(
"fileBasedDeviceInfo"
)
)
operator
fun
FileBasedDeviceInfo
.
unaryPlus
()
{
fileBasedDeviceInfo
(
this
.
filepath
)
}
}
/**
* 使用文件系统存储设备信息.
*/
@PlannedRemoval
(
"0.34.0"
)
@Deprecated
(
"use fileBasedDeviceInfo(filepath"
,
level
=
DeprecationLevel
.
ERROR
)
inline
class
FileBasedDeviceInfo
(
val
filepath
:
String
)
{
/**
* 使用 "device.json" 存储设备信息
*/
companion
object
ByDeviceDotJson
}
}
@OptIn
(
ExperimentalMultiplatform
::
class
)
@OptIn
(
ExperimentalMultiplatform
::
class
)
...
...
mirai-core/src/commonTest/kotlin/net/mamoe/mirai/message.data/CombinedMessageTest.kt
View file @
b8b749bf
package
net.mamoe.mirai.message.data
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
kotlin.test.Test
import
kotlin.test.Test
import
kotlin.test.assertEquals
import
kotlin.test.assertEquals
import
kotlin.time.ExperimentalTime
import
kotlin.time.measureTime
@OptIn
(
MiraiInternalAPI
::
class
)
internal
class
CombinedMessageTest
{
internal
class
CombinedMessageTest
{
@Test
@Test
fun
testAsSequence
()
{
fun
testAsSequence
()
{
var
message
:
Message
=
"Hello "
.
toMessage
()
var
message
:
Message
=
"Hello "
.
toMessage
()
...
@@ -32,84 +33,6 @@ internal class CombinedMessageTest {
...
@@ -32,84 +33,6 @@ internal class CombinedMessageTest {
(
message
as
CombinedMessage
).
asSequence
().
joinToString
(
separator
=
""
)
(
message
as
CombinedMessage
).
asSequence
().
joinToString
(
separator
=
""
)
)
)
}
}
private
val
toAdd
=
"1"
.
toMessage
()
@OptIn
(
ExperimentalTime
::
class
)
@Test
fun
speedTest
()
=
repeat
(
100
)
{
var
count
=
1L
repeat
(
Int
.
MAX_VALUE
)
{
count
++
}
var
combineMessage
:
Message
=
toAdd
println
(
"init combine ok "
+
measureTime
{
repeat
(
1000
)
{
combineMessage
+=
toAdd
}
}.
inMilliseconds
)
val
list
=
mutableListOf
<
Message
>()
println
(
"init messageChain ok "
+
measureTime
{
repeat
(
1000
)
{
list
+=
toAdd
}
}.
inMilliseconds
)
measureTime
{
list
.
joinToString
(
separator
=
""
)
}.
let
{
time
->
println
(
"list foreach: ${time.inMilliseconds} ms"
)
}
measureTime
{
(
combineMessage
as
CombinedMessage
).
iterator
().
joinToString
(
separator
=
""
)
}.
let
{
time
->
println
(
"combined iterate: ${time.inMilliseconds} ms"
)
}
measureTime
{
(
combineMessage
as
CombinedMessage
).
asSequence
().
joinToString
(
separator
=
""
)
}.
let
{
time
->
println
(
"combined sequence: ${time.inMilliseconds} ms"
)
}
repeat
(
5
)
{
println
()
}
}
@OptIn
(
ExperimentalTime
::
class
)
@Test
fun
testFastIteration
()
{
println
(
"start!"
)
println
(
"start!"
)
println
(
"start!"
)
println
(
"start!"
)
var
combineMessage
:
Message
=
toAdd
println
(
"init combine ok "
+
measureTime
{
repeat
(
1000
)
{
combineMessage
+=
toAdd
}
}.
inMilliseconds
)
measureTime
{
(
combineMessage
as
CombinedMessage
).
iterator
().
joinToString
(
separator
=
""
)
}.
let
{
time
->
println
(
"combine: ${time.inMilliseconds} ms"
)
}
}
}
}
fun
<
T
>
Iterator
<
T
>.
joinToString
(
fun
<
T
>
Iterator
<
T
>.
joinToString
(
...
@@ -140,7 +63,7 @@ fun <T, A : Appendable> Iterator<T>.joinTo(
...
@@ -140,7 +63,7 @@ fun <T, A : Appendable> Iterator<T>.joinTo(
buffer
.
appendElement
(
element
,
transform
)
buffer
.
appendElement
(
element
,
transform
)
}
else
break
}
else
break
}
}
if
(
limit
>=
0
&&
count
>
limi
t
)
buffer
.
append
(
truncated
)
if
(
limit
in
0
until
coun
t
)
buffer
.
append
(
truncated
)
buffer
.
append
(
postfix
)
buffer
.
append
(
postfix
)
return
buffer
return
buffer
}
}
...
...
mirai-core/src/commonTest/kotlin/net/mamoe/mirai/message.data/ConstrainSingleTest.kt
View file @
b8b749bf
...
@@ -10,9 +10,11 @@
...
@@ -10,9 +10,11 @@
package
net.mamoe.mirai.message.data
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
kotlin.test.Test
import
kotlin.test.Test
import
kotlin.test.assertEquals
import
kotlin.test.assertEquals
import
kotlin.test.assertSame
import
kotlin.test.assertSame
import
kotlin.test.assertTrue
@OptIn
(
MiraiExperimentalAPI
::
class
)
@OptIn
(
MiraiExperimentalAPI
::
class
)
...
@@ -25,7 +27,7 @@ internal class TestConstrainSingleMessage : ConstrainSingle<TestConstrainSingleM
...
@@ -25,7 +27,7 @@ internal class TestConstrainSingleMessage : ConstrainSingle<TestConstrainSingleM
override
fun
toString
():
String
=
"<TestConstrainSingleMessage#${super.hashCode()}>"
override
fun
toString
():
String
=
"<TestConstrainSingleMessage#${super.hashCode()}>"
override
fun
contentToString
():
String
{
override
fun
contentToString
():
String
{
TODO
(
"Not yet implemented"
)
return
""
}
}
override
val
key
:
Message
.
Key
<
TestConstrainSingleMessage
>
override
val
key
:
Message
.
Key
<
TestConstrainSingleMessage
>
...
@@ -46,16 +48,75 @@ internal class TestConstrainSingleMessage : ConstrainSingle<TestConstrainSingleM
...
@@ -46,16 +48,75 @@ internal class TestConstrainSingleMessage : ConstrainSingle<TestConstrainSingleM
}
}
}
}
@OptIn
(
MiraiExperimentalAPI
::
class
)
internal
class
ConstrainSingleTest
{
internal
class
ConstrainSingleTest
{
@OptIn
(
MiraiExperimentalAPI
::
class
)
@OptIn
(
MiraiInternalAPI
::
class
)
@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
@Test
fun
testConstrainSingleInPlus
()
{
fun
testSinglePlusChain
()
{
val
result
=
PlainText
(
"te"
)
+
buildMessageChain
{
add
(
TestConstrainSingleMessage
())
add
(
"st"
)
}
assertTrue
(
result
is
MessageChainImplByCollection
)
assertEquals
(
3
,
result
.
size
)
assertEquals
(
result
.
contentToString
(),
"test"
)
}
@Test
fun
testSinglePlusChainConstrain
()
{
val
chain
=
buildMessageChain
{
add
(
TestConstrainSingleMessage
())
add
(
"st"
)
}
val
result
=
TestConstrainSingleMessage
()
+
chain
assertSame
(
chain
,
result
)
assertEquals
(
2
,
result
.
size
)
assertEquals
(
result
.
contentToString
(),
"st"
)
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
()
val
new
=
TestConstrainSingleMessage
()
val
combined
=
(
TestConstrainSingleMessage
()
+
new
)
as
CombinedMessage
assertEquals
(
combined
.
left
,
EmptyMessageChain
)
val
result
=
buildMessageChain
{
assertSame
(
combined
.
tail
,
new
)
add
(
" "
)
add
(
Face
(
Face
.
hao
))
add
(
TestConstrainSingleMessage
())
add
(
PlainText
(
"ss"
)
+
" "
)
}
+
buildMessageChain
{
add
(
PlainText
(
"p "
))
add
(
new
)
add
(
PlainText
(
"test"
))
}
assertEquals
(
7
,
result
.
size
)
assertEquals
(
" [表情]ss p test"
,
result
.
contentToString
())
result
as
MessageChainImplByCollection
assertSame
(
new
,
result
.
delegate
.
toTypedArray
()[
2
])
}
}
@Test
// net.mamoe.mirai/message/data/MessageChain.kt:441
@Test
// net.mamoe.mirai/message/data/MessageChain.kt:441
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment