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.internal.TaggedDecoder
import kotlinx.serialization.modules.SerialModule
import net.mamoe.mirai.qqandroid.io.serialization.Jce
@OptIn(InternalSerializationApi::class) // 将来 kotlinx 修改后再复制过来 mirai.
@ -30,16 +29,13 @@ internal class JceDecoder(
val id = annotations.filterIsInstance<JceId>().single().id
// ?: 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(
id,
this.getElementDescriptor(index).isNullable
)
return JceTagCommon(id)
}
private fun SerialDescriptor.getJceTagId(index: Int): Int {
println("getTag: ${getElementName(index)}")
//println("getTag: ${getElementName(index)}")
return getElementAnnotations(index).filterIsInstance<JceId>().singleOrNull()?.id
?: 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 {
this@JceDecoder.pushTag(JceTag(0, false))
this@JceDecoder.pushTag(JceTagListElement)
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 decodeInt(): Int = error("illegal access")
override fun decodeLong(): Long = error("illegal access")
@ -75,7 +71,7 @@ internal class JceDecoder(
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
// 不要读下一个 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 {
this@JceDecoder.pushTag(JceTag(0, false))
this@JceDecoder.pushTag(JceTagListElement)
return this@JceDecoder.beginStructure(descriptor, *typeParams)
}
@ -105,9 +102,9 @@ internal class JceDecoder(
override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
println("decodeCollectionSize: ${descriptor.serialName}")
//println("decodeCollectionSize: ${descriptor.serialName}")
// 不读下一个 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() {
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) {
this@JceDecoder.endStructure(descriptor)
}
private var state: Boolean = true
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
return this@JceDecoder.beginStructure(descriptor, *typeParams)
}
@ -134,21 +133,22 @@ internal class JceDecoder(
override fun decodeLong(): Long = jce.useHead { jce.readJceLongValue(it) }
override fun decodeFloat(): Float = jce.useHead { jce.readJceFloatValue(it) }
override fun decodeDouble(): Double = jce.useHead { jce.readJceDoubleValue(it) }
override fun decodeBoolean(): Boolean = jce.useHead { jce.readJceBooleanValue(it) }
override fun decodeChar(): Char = decodeByte().toChar()
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeInt()
override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
println("decodeCollectionSize in MapReader: ${descriptor.serialName}")
//println("decodeCollectionSize in MapReader: ${descriptor.serialName}")
// 不读下一个 head
return jce.useHead { jce.readJceIntValue(it) }.also { println("listSize=$it") }
return jce.useHead { jce.readJceIntValue(it) }
}
}
override fun endStructure(descriptor: SerialDescriptor) {
println("endStructure: $descriptor")
//println("endStructure: $descriptor")
if (currentTagOrNull?.isSimpleByteArray == true) {
jce.prepareNextHead() // read to next head
}
@ -160,10 +160,10 @@ internal class JceDecoder(
val currentHead = jce.currentHeadOrNull ?: return
if (currentHead.type == Jce.STRUCT_END) {
jce.prepareNextHead()
println("current end")
//println("current end")
break
}
println("current $currentHead")
//println("current $currentHead")
jce.skipField(currentHead.type)
jce.prepareNextHead()
}
@ -174,24 +174,24 @@ internal class JceDecoder(
}
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
println()
println("beginStructure: ${descriptor.serialName}")
//println()
//println("beginStructure: ${descriptor.serialName}")
return when (descriptor.kind) {
is PrimitiveKind -> this@JceDecoder
StructureKind.MAP -> {
println("!! MAP")
//println("!! MAP")
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) {
it.checkType(Jce.MAP)
MapReader
}
}
StructureKind.LIST -> {
println("!! ByteArray")
println("decoderTag: $currentTagOrNull")
println("jceHead: " + jce.currentHeadOrNull)
//println("!! ByteArray")
//println("decoderTag: $currentTagOrNull")
//println("jceHead: " + jce.currentHeadOrNull)
return jce.skipToHeadAndUseIfPossibleOrFail(currentTag.id) {
println("listHead: $it")
//println("listHead: $it")
when (it.type) {
Jce.SIMPLE_LIST -> {
currentTag.isSimpleByteArray = true
@ -204,11 +204,11 @@ internal class JceDecoder(
}
}
StructureKind.CLASS -> {
val currentTag = currentTagOrNull ?: return this@JceDecoder
currentTagOrNull ?: return this@JceDecoder // outermost
println("!! CLASS")
println("decoderTag: $currentTag")
println("jceHead: " + jce.currentHeadOrNull)
//println("!! CLASS")
//println("decoderTag: $currentTag")
//println("jceHead: " + jce.currentHeadOrNull)
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) { jceHead ->
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 decodeElementIndex(descriptor: SerialDescriptor): Int {
val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE
@ -252,16 +244,6 @@ internal class JceDecoder(
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 =
jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) }

View File

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

View File

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

View File

@ -3,6 +3,7 @@
package net.mamoe.mirai.qqandroid.io.serialization
import kotlinx.io.core.buildPacket
import kotlinx.io.core.toByteArray
import kotlinx.io.core.writeFully
import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.Serializable
@ -271,8 +272,13 @@ internal class JceInputTest {
fun testMapStringByteArray() {
@Serializable
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 {
writeJceHead(MAP, 0)
@ -284,18 +290,20 @@ internal class JceInputTest {
it.forEach { (key, value) ->
writeJceHead(STRING1, 0)
writeByte(key.length.toByte())
writeStringUtf8(key)
writeFully(key.toByteArray())
writeJceHead(SIMPLE_LIST, 1)
writeJceHead(BYTE, 0)
writeJceHead(INT, 0)
writeInt(value.size)
writeFully(value)
}
}
}
assertEquals(
TestSerializableClassA(mapOf("str1" to byteArrayOf(2, 3, 4), "str2" to byteArrayOf(2, 3, 4))),
Jce.UTF_8.load(TestSerializableClassA.serializer(), input)
TestSerializableClassA(mapOf("str1" to byteArrayOf(2, 3, 4), "str2" to byteArrayOf(2, 3, 4))).toString(),
Jce.UTF_8.load(TestSerializableClassA.serializer(), input).toString()
)
}