Fix Map entry tags, remove debugging logs

This commit is contained in:
Him188 2020-03-08 17:44:34 +08:00
parent ce7af37ef4
commit c69cb6f3de
4 changed files with 60 additions and 77 deletions

View File

@ -15,7 +15,6 @@ import kotlinx.serialization.*
import kotlinx.serialization.builtins.AbstractDecoder import kotlinx.serialization.builtins.AbstractDecoder
import kotlinx.serialization.internal.TaggedDecoder import kotlinx.serialization.internal.TaggedDecoder
import kotlinx.serialization.modules.SerialModule import kotlinx.serialization.modules.SerialModule
import net.mamoe.mirai.qqandroid.io.serialization.Jce
@OptIn(InternalSerializationApi::class) // 将来 kotlinx 修改后再复制过来 mirai. @OptIn(InternalSerializationApi::class) // 将来 kotlinx 修改后再复制过来 mirai.
@ -30,16 +29,13 @@ internal class JceDecoder(
val id = annotations.filterIsInstance<JceId>().single().id val id = annotations.filterIsInstance<JceId>().single().id
// ?: error("cannot find @JceId or @ProtoId for ${this.getElementName(index)} in ${this.serialName}") // ?: error("cannot find @JceId or @ProtoId for ${this.getElementName(index)} in ${this.serialName}")
println("getTag: ${this.getElementName(index)}=$id") //println("getTag: ${this.getElementName(index)}=$id")
return JceTag( return JceTagCommon(id)
id,
this.getElementDescriptor(index).isNullable
)
} }
private fun SerialDescriptor.getJceTagId(index: Int): Int { private fun SerialDescriptor.getJceTagId(index: Int): Int {
println("getTag: ${getElementName(index)}") //println("getTag: ${getElementName(index)}")
return getElementAnnotations(index).filterIsInstance<JceId>().singleOrNull()?.id return getElementAnnotations(index).filterIsInstance<JceId>().singleOrNull()?.id
?: error("missing @JceId for ${getElementName(index)} in ${this.serialName}") ?: error("missing @JceId for ${getElementName(index)} in ${this.serialName}")
} }
@ -54,11 +50,11 @@ internal class JceDecoder(
} }
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder { override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
this@JceDecoder.pushTag(JceTag(0, false)) this@JceDecoder.pushTag(JceTagListElement)
return this@JceDecoder.beginStructure(descriptor, *typeParams) return this@JceDecoder.beginStructure(descriptor, *typeParams)
} }
override fun decodeByte(): Byte = jce.input.readByte().also { println("decodeByte: $it") } override fun decodeByte(): Byte = jce.input.readByte()
override fun decodeShort(): Short = error("illegal access") override fun decodeShort(): Short = error("illegal access")
override fun decodeInt(): Int = error("illegal access") override fun decodeInt(): Int = error("illegal access")
override fun decodeLong(): Long = error("illegal access") override fun decodeLong(): Long = error("illegal access")
@ -75,7 +71,7 @@ internal class JceDecoder(
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int { override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
// 不要读下一个 head // 不要读下一个 head
return jce.currentHead.let { jce.readJceIntValue(it) }.also { println("simpleListSize=$it") } return jce.currentHead.let { jce.readJceIntValue(it) }
} }
} }
@ -89,7 +85,8 @@ internal class JceDecoder(
} }
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder { override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
this@JceDecoder.pushTag(JceTag(0, false)) this@JceDecoder.pushTag(JceTagListElement)
return this@JceDecoder.beginStructure(descriptor, *typeParams) return this@JceDecoder.beginStructure(descriptor, *typeParams)
} }
@ -105,9 +102,9 @@ internal class JceDecoder(
override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) } override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int { override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
println("decodeCollectionSize: ${descriptor.serialName}") //println("decodeCollectionSize: ${descriptor.serialName}")
// 不读下一个 head // 不读下一个 head
return jce.useHead { jce.readJceIntValue(it) }.also { println("listSize=$it") } return jce.useHead { jce.readJceIntValue(it) }
} }
} }
@ -116,14 +113,16 @@ internal class JceDecoder(
private inner class MapReaderImpl : AbstractDecoder() { private inner class MapReaderImpl : AbstractDecoder() {
override fun decodeSequentially(): Boolean = true override fun decodeSequentially(): Boolean = true
override fun decodeElementIndex(descriptor: SerialDescriptor): Int = error("should not be reached") override fun decodeElementIndex(descriptor: SerialDescriptor): Int = error("stub")
override fun endStructure(descriptor: SerialDescriptor) { override fun endStructure(descriptor: SerialDescriptor) {
this@JceDecoder.endStructure(descriptor) this@JceDecoder.endStructure(descriptor)
} }
private var state: Boolean = true private var state: Boolean = true
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder { override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
this@JceDecoder.pushTag(JceTag(if (state) 0 else 1, false)) this@JceDecoder.pushTag(if (jce.currentHead.tag == 0) JceTagMapEntryKey else JceTagMapEntryValue)
state = !state state = !state
return this@JceDecoder.beginStructure(descriptor, *typeParams) return this@JceDecoder.beginStructure(descriptor, *typeParams)
} }
@ -134,21 +133,22 @@ internal class JceDecoder(
override fun decodeLong(): Long = jce.useHead { jce.readJceLongValue(it) } override fun decodeLong(): Long = jce.useHead { jce.readJceLongValue(it) }
override fun decodeFloat(): Float = jce.useHead { jce.readJceFloatValue(it) } override fun decodeFloat(): Float = jce.useHead { jce.readJceFloatValue(it) }
override fun decodeDouble(): Double = jce.useHead { jce.readJceDoubleValue(it) } override fun decodeDouble(): Double = jce.useHead { jce.readJceDoubleValue(it) }
override fun decodeBoolean(): Boolean = jce.useHead { jce.readJceBooleanValue(it) } override fun decodeBoolean(): Boolean = jce.useHead { jce.readJceBooleanValue(it) }
override fun decodeChar(): Char = decodeByte().toChar() override fun decodeChar(): Char = decodeByte().toChar()
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeInt() override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeInt()
override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) } override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int { override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
println("decodeCollectionSize in MapReader: ${descriptor.serialName}") //println("decodeCollectionSize in MapReader: ${descriptor.serialName}")
// 不读下一个 head // 不读下一个 head
return jce.useHead { jce.readJceIntValue(it) }.also { println("listSize=$it") } return jce.useHead { jce.readJceIntValue(it) }
} }
} }
override fun endStructure(descriptor: SerialDescriptor) { override fun endStructure(descriptor: SerialDescriptor) {
println("endStructure: $descriptor") //println("endStructure: $descriptor")
if (currentTagOrNull?.isSimpleByteArray == true) { if (currentTagOrNull?.isSimpleByteArray == true) {
jce.prepareNextHead() // read to next head jce.prepareNextHead() // read to next head
} }
@ -160,10 +160,10 @@ internal class JceDecoder(
val currentHead = jce.currentHeadOrNull ?: return val currentHead = jce.currentHeadOrNull ?: return
if (currentHead.type == Jce.STRUCT_END) { if (currentHead.type == Jce.STRUCT_END) {
jce.prepareNextHead() jce.prepareNextHead()
println("current end") //println("current end")
break break
} }
println("current $currentHead") //println("current $currentHead")
jce.skipField(currentHead.type) jce.skipField(currentHead.type)
jce.prepareNextHead() jce.prepareNextHead()
} }
@ -174,24 +174,24 @@ internal class JceDecoder(
} }
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder { override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
println() //println()
println("beginStructure: ${descriptor.serialName}") //println("beginStructure: ${descriptor.serialName}")
return when (descriptor.kind) { return when (descriptor.kind) {
is PrimitiveKind -> this@JceDecoder is PrimitiveKind -> this@JceDecoder
StructureKind.MAP -> { StructureKind.MAP -> {
println("!! MAP") //println("!! MAP")
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) { return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) {
it.checkType(Jce.MAP) it.checkType(Jce.MAP)
MapReader MapReader
} }
} }
StructureKind.LIST -> { StructureKind.LIST -> {
println("!! ByteArray") //println("!! ByteArray")
println("decoderTag: $currentTagOrNull") //println("decoderTag: $currentTagOrNull")
println("jceHead: " + jce.currentHeadOrNull) //println("jceHead: " + jce.currentHeadOrNull)
return jce.skipToHeadAndUseIfPossibleOrFail(currentTag.id) { return jce.skipToHeadAndUseIfPossibleOrFail(currentTag.id) {
println("listHead: $it") //println("listHead: $it")
when (it.type) { when (it.type) {
Jce.SIMPLE_LIST -> { Jce.SIMPLE_LIST -> {
currentTag.isSimpleByteArray = true currentTag.isSimpleByteArray = true
@ -204,11 +204,11 @@ internal class JceDecoder(
} }
} }
StructureKind.CLASS -> { StructureKind.CLASS -> {
val currentTag = currentTagOrNull ?: return this@JceDecoder currentTagOrNull ?: return this@JceDecoder // outermost
println("!! CLASS") //println("!! CLASS")
println("decoderTag: $currentTag") //println("decoderTag: $currentTag")
println("jceHead: " + jce.currentHeadOrNull) //println("jceHead: " + jce.currentHeadOrNull)
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) { jceHead -> return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) { jceHead ->
jceHead.checkType(Jce.STRUCT_BEGIN) jceHead.checkType(Jce.STRUCT_BEGIN)
@ -227,14 +227,6 @@ internal class JceDecoder(
} }
} }
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
println(
"decodeSerializableValue: ${deserializer.descriptor.toString().substringBefore('(')
.substringAfterLast('.')}"
)
return super.decodeSerializableValue(deserializer)
}
override fun decodeSequentially(): Boolean = false override fun decodeSequentially(): Boolean = false
override fun decodeElementIndex(descriptor: SerialDescriptor): Int { override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE
@ -252,16 +244,6 @@ internal class JceDecoder(
return CompositeDecoder.READ_DONE // optional support return CompositeDecoder.READ_DONE // optional support
} }
override fun decodeTaggedNull(tag: JceTag): Nothing? {
println("decodeTaggedNull")
return super.decodeTaggedNull(tag)
}
override fun decodeTaggedValue(tag: JceTag): Any {
println("decodeTaggedValue")
return super.decodeTaggedValue(tag)
}
override fun decodeTaggedInt(tag: JceTag): Int = override fun decodeTaggedInt(tag: JceTag): Int =
jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) }

View File

@ -166,7 +166,7 @@ internal class JceInput(
// region readers // region readers
fun readJceIntValue(head: JceHead): Int { fun readJceIntValue(head: JceHead): Int {
println("readJceIntValue: $head") //println("readJceIntValue: $head")
return when (head.type) { return when (head.type) {
Jce.ZERO_TYPE -> 0 Jce.ZERO_TYPE -> 0
Jce.BYTE -> input.readByte().toInt() Jce.BYTE -> input.readByte().toInt()
@ -197,7 +197,7 @@ internal class JceInput(
} }
fun readJceByteValue(head: JceHead): Byte { fun readJceByteValue(head: JceHead): Byte {
println("readJceByteValue: $head") //println("readJceByteValue: $head")
return when (head.type) { return when (head.type) {
Jce.ZERO_TYPE -> 0 Jce.ZERO_TYPE -> 0
Jce.BYTE -> input.readByte() Jce.BYTE -> input.readByte()
@ -215,6 +215,7 @@ internal class JceInput(
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
fun readJceStringValue(head: JceHead): String { fun readJceStringValue(head: JceHead): String {
//println("readJceStringValue: $head")
return when (head.type) { return when (head.type) {
Jce.STRING1 -> input.readString(input.readUByte().toInt(), charset = charset.kotlinCharset) Jce.STRING1 -> input.readString(input.readUByte().toInt(), charset = charset.kotlinCharset)
Jce.STRING4 -> input.readString( Jce.STRING4 -> input.readString(

View File

@ -28,41 +28,33 @@ annotation class JceId(val id: Int)
@PublishedApi @PublishedApi
internal abstract class JceTag { internal abstract class JceTag {
abstract val id: Int abstract val id: Int
abstract val isNullable: Boolean
internal var isSimpleByteArray: Boolean = false internal var isSimpleByteArray: Boolean = false
} }
internal sealed class JceTagListElement( internal object JceTagListElement : JceTag() {
override val isNullable: Boolean
) : JceTag(){
override val id: Int get() = 0 override val id: Int get() = 0
override fun toString(): String {
object Nullable : JceTagListElement(true) return "JceTagListElement"
object NotNull : JceTagListElement(false) }
} }
internal sealed class JceTagMapEntryKey( internal object JceTagMapEntryKey : JceTag() {
override val isNullable: Boolean
) : JceTag(){
override val id: Int get() = 0 override val id: Int get() = 0
override fun toString(): String {
object Nullable : JceTagMapEntryKey(true) return "JceTagMapEntryKey"
object NotNull : JceTagMapEntryKey(false) }
} }
internal sealed class JceTagMapEntryValue( internal object JceTagMapEntryValue : JceTag() {
override val isNullable: Boolean
) : JceTag() {
override val id: Int get() = 1 override val id: Int get() = 1
override fun toString(): String {
object Nullable : JceTagMapEntryValue(true) return "JceTagMapEntryValue"
object NotNull : JceTagMapEntryValue(false) }
} }
internal data class JceTagCommon( internal data class JceTagCommon(
override val id: Int, override val id: Int
override val isNullable: Boolean
) : JceTag() ) : JceTag()
fun JceHead.checkType(type: Byte) { fun JceHead.checkType(type: Byte) {

View File

@ -3,6 +3,7 @@
package net.mamoe.mirai.qqandroid.io.serialization package net.mamoe.mirai.qqandroid.io.serialization
import kotlinx.io.core.buildPacket import kotlinx.io.core.buildPacket
import kotlinx.io.core.toByteArray
import kotlinx.io.core.writeFully import kotlinx.io.core.writeFully
import kotlinx.serialization.MissingFieldException import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -271,8 +272,13 @@ internal class JceInputTest {
fun testMapStringByteArray() { fun testMapStringByteArray() {
@Serializable @Serializable
data class TestSerializableClassA( data class TestSerializableClassA(
@JceId(0) val byteArray: Map<String, ByteArray> @JceId(0) val map: Map<String, ByteArray>
) ) {
override fun toString(): String {
@Suppress("EXPERIMENTAL_API_USAGE")
return map.entries.joinToString { "${it.key}=${it.value.contentToString()}" }
}
}
val input = buildPacket { val input = buildPacket {
writeJceHead(MAP, 0) writeJceHead(MAP, 0)
@ -284,18 +290,20 @@ internal class JceInputTest {
it.forEach { (key, value) -> it.forEach { (key, value) ->
writeJceHead(STRING1, 0) writeJceHead(STRING1, 0)
writeByte(key.length.toByte()) writeByte(key.length.toByte())
writeStringUtf8(key) writeFully(key.toByteArray())
writeJceHead(SIMPLE_LIST, 1) writeJceHead(SIMPLE_LIST, 1)
writeJceHead(BYTE, 0) writeJceHead(BYTE, 0)
writeJceHead(INT, 0)
writeInt(value.size)
writeFully(value) writeFully(value)
} }
} }
} }
assertEquals( assertEquals(
TestSerializableClassA(mapOf("str1" to byteArrayOf(2, 3, 4), "str2" to byteArrayOf(2, 3, 4))), TestSerializableClassA(mapOf("str1" to byteArrayOf(2, 3, 4), "str2" to byteArrayOf(2, 3, 4))).toString(),
Jce.UTF_8.load(TestSerializableClassA.serializer(), input) Jce.UTF_8.load(TestSerializableClassA.serializer(), input).toString()
) )
} }