Commit ac6f411e authored by Him188's avatar Him188

Add `equals` and `hashCode` to `Message`s

parent db8cb84c
...@@ -29,7 +29,8 @@ import kotlin.jvm.JvmSynthetic ...@@ -29,7 +29,8 @@ import kotlin.jvm.JvmSynthetic
* *
* @see AtAll 全体成员 * @see AtAll 全体成员
*/ */
class At data class At
@Suppress("DataClassPrivateConstructor")
private constructor(val target: Long, val display: String) : private constructor(val target: Long, val display: String) :
MessageContent, MessageContent,
CharSequence by display, CharSequence by display,
...@@ -40,6 +41,10 @@ private constructor(val target: Long, val display: String) : ...@@ -40,6 +41,10 @@ private constructor(val target: Long, val display: String) :
*/ */
constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}") constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}")
override fun equals(other: Any?): Boolean {
return other is At && other.target == this.target && other.display == this.display
}
override fun toString(): String = "[mirai:at:$target]" override fun toString(): String = "[mirai:at:$target]"
override fun contentToString(): String = this.display override fun contentToString(): String = this.display
...@@ -57,6 +62,20 @@ private constructor(val target: Long, val display: String) : ...@@ -57,6 +62,20 @@ private constructor(val target: Long, val display: String) :
} }
// 自动为消息补充 " " // 自动为消息补充 " "
override fun followedBy(tail: Message): MessageChain {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)
}
return super.followedBy(PlainText(" ")) + tail
}
override fun hashCode(): Int {
var result = target.hashCode()
result = 31 * result + display.hashCode()
return result
}
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
@Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE") @Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -65,13 +84,6 @@ private constructor(val target: Long, val display: String) : ...@@ -65,13 +84,6 @@ private constructor(val target: Long, val display: String) :
override fun followedBy1(tail: Message): CombinedMessage { override fun followedBy1(tail: Message): CombinedMessage {
return followedByInternalForBinaryCompatibility(tail) return followedByInternalForBinaryCompatibility(tail)
} }
override fun followedBy(tail: Message): MessageChain {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)
}
return super.followedBy(PlainText(" ")) + tail
}
} }
/** /**
......
...@@ -41,6 +41,13 @@ object AtAll : ...@@ -41,6 +41,13 @@ object AtAll :
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
override fun toString(): String = "[mirai:atall]" override fun toString(): String = "[mirai:atall]"
override fun contentToString(): String = display override fun contentToString(): String = display
override fun equals(other: Any?): Boolean {
return other === this
}
override fun hashCode(): Int {
return display.hashCode()
}
// 自动为消息补充 " " // 自动为消息补充 " "
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
......
...@@ -14,6 +14,7 @@ package net.mamoe.mirai.message.data ...@@ -14,6 +14,7 @@ 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 kotlin.jvm.JvmField
import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
...@@ -30,8 +31,8 @@ import kotlin.jvm.JvmSynthetic ...@@ -30,8 +31,8 @@ import kotlin.jvm.JvmSynthetic
*/ */
internal class CombinedMessage internal class CombinedMessage
internal constructor( internal constructor(
internal val left: Message, // 必须已经完成 constrain single @JvmField internal val left: Message, // 必须已经完成 constrain single
internal val tail: Message @JvmField internal val tail: Message
) : Message, MessageChain { ) : Message, MessageChain {
@OptIn(MiraiExperimentalAPI::class) @OptIn(MiraiExperimentalAPI::class)
fun asSequence(): Sequence<SingleMessage> = sequence { fun asSequence(): Sequence<SingleMessage> = sequence {
...@@ -49,6 +50,10 @@ internal constructor( ...@@ -49,6 +50,10 @@ internal constructor(
size size
} }
override fun equals(other: Any?): Boolean {
return other is CombinedMessage && other.left == this.left && other.tail == this.tail
}
@OptIn(MiraiExperimentalAPI::class) @OptIn(MiraiExperimentalAPI::class)
override fun toString(): String { override fun toString(): String {
return tail.toString() + left.toString() return tail.toString() + left.toString()
...@@ -57,6 +62,12 @@ internal constructor( ...@@ -57,6 +62,12 @@ internal constructor(
override fun contentToString(): String { override fun contentToString(): String {
return left.contentToString() + tail.contentToString() return left.contentToString() + tail.contentToString()
} }
override fun hashCode(): Int {
var result = left.hashCode()
result = 31 * result + tail.hashCode()
return result
}
} }
@JvmSynthetic @JvmSynthetic
......
...@@ -18,15 +18,19 @@ import kotlin.jvm.JvmName ...@@ -18,15 +18,19 @@ import kotlin.jvm.JvmName
/** /**
* QQ 自带表情 * QQ 自带表情
*/ */
class Face private constructor(val id: Int, private val stringValue: String) : data class Face
@Suppress("DataClassPrivateConstructor")
private constructor(val id: Int, private val stringValue: String) : // used in delegation
MessageContent, MessageContent,
CharSequence by stringValue, Comparable<String> by stringValue { CharSequence by stringValue, Comparable<String> by stringValue {
constructor(id: Int) : this(id, "[mirai:face:$id]") constructor(id: Int) : this(id, "[mirai:face:$id]")
override fun toString(): String = stringValue override fun toString(): String = stringValue
override fun contentToString(): String = "[表情]" override fun contentToString(): String = "[表情]"
override fun equals(other: Any?): Boolean = other is Face && other.id == this.id
override fun hashCode(): Int = id
/** /**
* @author LamGC * @author LamGC
*/ */
......
...@@ -43,7 +43,7 @@ sealed class HummerMessage : MessageContent { ...@@ -43,7 +43,7 @@ sealed class HummerMessage : MessageContent {
*/ */
@SinceMirai("0.31.0") @SinceMirai("0.31.0")
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常量") constructor( data class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常量") constructor(
@MiraiExperimentalAPI @MiraiExperimentalAPI
val type: Int, val type: Int,
@MiraiExperimentalAPI @MiraiExperimentalAPI
...@@ -87,12 +87,21 @@ class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常量") ...@@ -87,12 +87,21 @@ class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常量")
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
stringValue.subSequence(startIndex, endIndex) stringValue.subSequence(startIndex, endIndex)
override fun contentToString(): String { override fun contentToString(): String = "[戳一戳]"
return "[戳一戳]"
} @OptIn(MiraiExperimentalAPI::class)
override fun equals(other: Any?): Boolean = other is PokeMessage && other.type == this.type && other.id == this.id
override fun compareTo(other: String): Int = stringValue.compareTo(other) override fun compareTo(other: String): Int = stringValue.compareTo(other)
@OptIn(MiraiExperimentalAPI::class)
override fun hashCode(): Int {
var result = type
result = 31 * result + id
result = 31 * result + stringValue.hashCode()
return result
}
//businessType=0x00000001(1) //businessType=0x00000001(1)
//pbElem=08 01 18 00 20 FF FF FF FF 0F 2A 00 32 00 38 00 50 00 //pbElem=08 01 18 00 20 FF FF FF FF 0F 2A 00 32 00 38 00 50 00
//serviceType=0x00000002(2) //serviceType=0x00000002(2)
...@@ -178,7 +187,7 @@ inline fun FriendImage.flash(): FriendFlashImage = FlashImage(this) as FriendFla ...@@ -178,7 +187,7 @@ inline fun FriendImage.flash(): FriendFlashImage = FlashImage(this) as FriendFla
* @see FlashImage.invoke * @see FlashImage.invoke
*/ */
@SinceMirai("0.33.0") @SinceMirai("0.33.0")
class GroupFlashImage(override val image: GroupImage) : FlashImage() { data class GroupFlashImage(override val image: GroupImage) : FlashImage() {
companion object Key : Message.Key<GroupFlashImage> { companion object Key : Message.Key<GroupFlashImage> {
override val typeName: String override val typeName: String
get() = "GroupFlashImage" get() = "GroupFlashImage"
...@@ -189,7 +198,7 @@ class GroupFlashImage(override val image: GroupImage) : FlashImage() { ...@@ -189,7 +198,7 @@ class GroupFlashImage(override val image: GroupImage) : FlashImage() {
* @see FlashImage.invoke * @see FlashImage.invoke
*/ */
@SinceMirai("0.33.0") @SinceMirai("0.33.0")
class FriendFlashImage(override val image: FriendImage) : FlashImage() { data class FriendFlashImage(override val image: FriendImage) : FlashImage() {
companion object Key : Message.Key<FriendFlashImage> { companion object Key : Message.Key<FriendFlashImage> {
override val typeName: String override val typeName: String
get() = "FriendFlashImage" get() = "FriendFlashImage"
......
...@@ -212,7 +212,7 @@ data class OfflineGroupImage( ...@@ -212,7 +212,7 @@ data class OfflineGroupImage(
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return other is OfflineGroupImage && other.md5.contentEquals(this.md5) && other.filepath == this.filepath return other is OfflineGroupImage && other::class == this::class && other.md5.contentEquals(this.md5) && other.filepath == this.filepath
} }
} }
...@@ -276,8 +276,8 @@ data class OfflineFriendImage( ...@@ -276,8 +276,8 @@ data class OfflineFriendImage(
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return other is OfflineFriendImage && other.md5 return other is OfflineFriendImage && other::class == this::class &&
.contentEquals(this.md5) && other.resourceId == this.resourceId other.md5.contentEquals(this.md5) && other.resourceId == this.resourceId
} }
} }
...@@ -290,7 +290,10 @@ abstract class OnlineFriendImage : FriendImage(), OnlineImage ...@@ -290,7 +290,10 @@ abstract class OnlineFriendImage : FriendImage(), OnlineImage
// endregion // endregion
//////////////////////
// region internal // region internal
//////////////////////
private val EMPTY_BYTE_ARRAY = ByteArray(0) private val EMPTY_BYTE_ARRAY = ByteArray(0)
......
...@@ -100,8 +100,6 @@ interface Message { ...@@ -100,8 +100,6 @@ interface Message {
* ``` * ```
*/ */
@SinceMirai("0.34.0") @SinceMirai("0.34.0")
@Suppress("DEPRECATION_ERROR")
@OptIn(MiraiInternalAPI::class)
@JvmSynthetic // in java they should use `plus` instead @JvmSynthetic // in java they should use `plus` instead
fun followedBy(tail: Message): MessageChain = followedByImpl(tail) fun followedBy(tail: Message): MessageChain = followedByImpl(tail)
......
...@@ -373,6 +373,7 @@ object EmptyMessageChain : MessageChain, Iterator<SingleMessage> { ...@@ -373,6 +373,7 @@ object EmptyMessageChain : MessageChain, Iterator<SingleMessage> {
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 fun equals(other: Any?): Boolean = other === this
override fun iterator(): Iterator<SingleMessage> = this override fun iterator(): Iterator<SingleMessage> = this
override fun hasNext(): Boolean = false override fun hasNext(): Boolean = false
......
...@@ -22,7 +22,7 @@ import kotlin.jvm.JvmSynthetic ...@@ -22,7 +22,7 @@ import kotlin.jvm.JvmSynthetic
* *
* 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus] * 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus]
*/ */
class PlainText(val stringValue: String) : data class PlainText(val stringValue: String) :
MessageContent, MessageContent,
Comparable<String> by stringValue, Comparable<String> by stringValue,
CharSequence by stringValue { CharSequence by stringValue {
...@@ -33,14 +33,6 @@ class PlainText(val stringValue: String) : ...@@ -33,14 +33,6 @@ class PlainText(val stringValue: String) :
override fun toString(): String = stringValue override fun toString(): String = stringValue
override fun contentToString(): String = stringValue override fun contentToString(): String = stringValue
override fun equals(other: Any?): Boolean {
return other is PlainText && other.stringValue == this.stringValue
}
override fun hashCode(): Int {
return stringValue.hashCode()
}
companion object Key : Message.Key<PlainText> { companion object Key : Message.Key<PlainText> {
override val typeName: String override val typeName: String
get() = "PlainText" get() = "PlainText"
......
...@@ -46,6 +46,8 @@ class QuoteReply(val source: MessageSource) : Message, MessageMetadata, Constrai ...@@ -46,6 +46,8 @@ class QuoteReply(val source: MessageSource) : Message, MessageMetadata, Constrai
override fun toString(): String = "[mirai:quote:${source.id}]" override fun toString(): String = "[mirai:quote:${source.id}]"
override fun contentToString(): String = "" override fun contentToString(): String = ""
override fun equals(other: Any?): Boolean = other is QuoteReply && other.source == this.source
override fun hashCode(): Int = source.hashCode()
} }
@get:JvmSynthetic @get:JvmSynthetic
......
...@@ -33,6 +33,7 @@ interface RichMessage : MessageContent { ...@@ -33,6 +33,7 @@ interface RichMessage : MessageContent {
override fun contentToString(): String = this.content override fun contentToString(): String = this.content
@MiraiExperimentalAPI
@SinceMirai("0.30.0") @SinceMirai("0.30.0")
companion object Templates : Message.Key<RichMessage> { companion object Templates : Message.Key<RichMessage> {
...@@ -77,7 +78,7 @@ interface RichMessage : MessageContent { ...@@ -77,7 +78,7 @@ interface RichMessage : MessageContent {
* @param content 一般是 json * @param content 一般是 json
*/ */
@SinceMirai("0.27.0") @SinceMirai("0.27.0")
class LightApp constructor(override val content: String) : RichMessage { data class LightApp(override val content: String) : RichMessage {
companion object Key : Message.Key<LightApp> { companion object Key : Message.Key<LightApp> {
override val typeName: String get() = "LightApp" override val typeName: String get() = "LightApp"
} }
...@@ -97,6 +98,19 @@ open class ServiceMessage(@MiraiExperimentalAPI val serviceId: Int, final overri ...@@ -97,6 +98,19 @@ open class ServiceMessage(@MiraiExperimentalAPI val serviceId: Int, final overri
} }
final override fun toString(): String = "[mirai:service:$serviceId,$content]" final override fun toString(): String = "[mirai:service:$serviceId,$content]"
final override fun equals(other: Any?): Boolean {
if (other == null) return false
if (other::class != this::class) return false
other as ServiceMessage
return other.serviceId == this.serviceId && other.content == this.content
}
final override fun hashCode(): Int {
var result = serviceId
result = 31 * result + content.hashCode()
return result
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment