package net.sergeych.bipack import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.AbstractDecoder import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.modules.EmptySerializersModule import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.serializer import net.sergeych.bintools.CRC import net.sergeych.bintools.DataSource import net.sergeych.bintools.readNumber import net.sergeych.bintools.toDataSource class BipackDecoder(val input: DataSource, var elementsCount: Int = 0) : AbstractDecoder() { private var elementIndex = 0 override val serializersModule: SerializersModule = EmptySerializersModule override fun decodeBoolean(): Boolean = input.readByte().toInt() != 0 override fun decodeByte(): Byte = input.readByte() override fun decodeShort(): Short = input.readNumber() override fun decodeInt(): Int = input.readNumber() override fun decodeLong(): Long = input.readNumber() override fun decodeFloat(): Float = input.readFloat() override fun decodeDouble(): Double = input.readDouble() override fun decodeChar(): Char = Char(input.readNumber().toInt()) fun readBytes(): ByteArray { val length = input.readNumber() return input.readBytes(length.toInt()) } override fun decodeString(): String = readBytes().decodeToString() override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = input.readNumber().toInt() override fun decodeElementIndex(descriptor: SerialDescriptor): Int { if (elementIndex >= elementsCount) return CompositeDecoder.DECODE_DONE return elementIndex++ } override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { var count = descriptor.elementsCount for( a in descriptor.annotations ) { if( a is ExtendableFormat ) count = input.readNumber().toInt() else if( a is Framed ) { val code = CRC.crc32(descriptor.serialName.encodeToByteArray()) val actual = input.readU32() if( code != actual ) throw InvalidFrameException() } } return BipackDecoder(input, count) } override fun decodeCollectionSize(descriptor: SerialDescriptor): Int = input.readNumber().toInt().also { elementsCount = it } override fun decodeNotNullMark(): Boolean = decodeBoolean() @ExperimentalSerializationApi override fun decodeNull(): Nothing? = null companion object { fun decode(source: DataSource, deserializer: DeserializationStrategy): T = BipackDecoder(source).decodeSerializableValue(deserializer) inline fun decode(source: DataSource): T = decode(source, serializer()) inline fun decode(source: ByteArray): T = decode(source.toDataSource(), serializer()) } }