BiPack: added @FixedSize for collection serialization
This commit is contained in:
1 parent
bd19570dec
commit
204f73f045
6 files changed
+156
-91
No files matched your search
@@ -15,10 +15,12 @@ import net.sergeych.bintools.*
|
||||
* Decode BiPack format. Note that it relies on [DataSource] so can throw [DataSource.EndOfData]
|
||||
* excpetion. Specific frames when used can throw [InvalidFrameException] and its derivatives.e
|
||||
*/
|
||||
class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isCollection: Boolean = false) : AbstractDecoder() {
|
||||
class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isCollection: Boolean = false,
|
||||
val hasFixedSize: Boolean = false) : AbstractDecoder() {
|
||||
private var elementIndex = 0
|
||||
|
||||
private var nextIsUnsigned = false
|
||||
private var fixedSize = -1
|
||||
|
||||
override val serializersModule: SerializersModule = EmptySerializersModule
|
||||
override fun decodeBoolean(): Boolean = input.readByte().toInt() != 0
|
||||
@@ -41,7 +43,13 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
|
||||
|
||||
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
|
||||
if (elementIndex >= elementsCount) return CompositeDecoder.DECODE_DONE
|
||||
nextIsUnsigned = descriptor.getElementAnnotations(elementIndex).any { it is Unsigned }
|
||||
nextIsUnsigned = false
|
||||
for( a in descriptor.getElementAnnotations(elementIndex)) {
|
||||
when(a) {
|
||||
is Unsigned -> nextIsUnsigned = true
|
||||
is FixedSize -> fixedSize = a.size
|
||||
}
|
||||
}
|
||||
return elementIndex++
|
||||
}
|
||||
|
||||
@@ -57,7 +65,7 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
|
||||
|
||||
// Note: we should read from 'source' explicitely as it might ve
|
||||
// CRC-calculating one, and the fields below are CRC protected too:
|
||||
var count = descriptor.elementsCount
|
||||
var count = if( fixedSize >= 0 ) fixedSize else descriptor.elementsCount
|
||||
for (a in descriptor.annotations) {
|
||||
if (a is Extendable)
|
||||
count = source.readVarUInt().toInt()
|
||||
@@ -71,11 +79,14 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
|
||||
}
|
||||
}
|
||||
// println("bestr ${descriptor.serialName} d/r ${descriptor.elementsCount}/$count")
|
||||
return BipackDecoder(source, count, isCollection)
|
||||
return BipackDecoder(source, count, isCollection, fixedSize >= 0)
|
||||
}
|
||||
|
||||
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
|
||||
return input.readNumber<UInt>().toInt()
|
||||
return if( hasFixedSize )
|
||||
elementsCount
|
||||
else
|
||||
input.readNumber<UInt>().toInt()
|
||||
}
|
||||
|
||||
override fun endStructure(descriptor: SerialDescriptor) {
|
||||
|
||||
@@ -12,12 +12,19 @@ import net.sergeych.bintools.*
|
||||
class BipackEncoder(val output: DataSink) : AbstractEncoder() {
|
||||
|
||||
private var nextIsUnsigned = false
|
||||
private var fixedSize: Int = -1
|
||||
|
||||
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
|
||||
return super.encodeElement(descriptor, index).also {
|
||||
nextIsUnsigned = descriptor.getElementAnnotations(index).any { it is Unsigned }
|
||||
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean =
|
||||
super.encodeElement(descriptor, index).also {
|
||||
nextIsUnsigned = false
|
||||
for (a in descriptor.getElementAnnotations(index)) {
|
||||
when (a) {
|
||||
is Unsigned -> nextIsUnsigned = true
|
||||
is FixedSize -> fixedSize = a.size
|
||||
}
|
||||
}
|
||||
// nextIsUnsigned = descriptor.getElementAnnotations(index).any { it is Unsigned }
|
||||
}
|
||||
}
|
||||
|
||||
override val serializersModule: SerializersModule = EmptySerializersModule
|
||||
override fun encodeBoolean(value: Boolean) = output.writeByte(if (value) 1 else 0)
|
||||
@@ -27,12 +34,9 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
|
||||
else
|
||||
output.writeNumber(value.toInt())
|
||||
|
||||
override fun encodeInt(value: Int) {
|
||||
if (nextIsUnsigned)
|
||||
output.writeNumber(value.toUInt())
|
||||
else
|
||||
output.writeNumber(value)
|
||||
}
|
||||
override fun encodeInt(value: Int) =
|
||||
if (nextIsUnsigned) output.writeNumber(value.toUInt())
|
||||
else output.writeNumber(value)
|
||||
|
||||
fun encodeUInt(value: UInt) = output.writeNumber(value)
|
||||
override fun encodeLong(value: Long) = if (nextIsUnsigned)
|
||||
@@ -56,7 +60,11 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
|
||||
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = output.writeNumber(index.toUInt())
|
||||
|
||||
override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
|
||||
encodeUInt(collectionSize.toUInt())
|
||||
if (fixedSize < 0)
|
||||
encodeUInt(collectionSize.toUInt())
|
||||
else if (collectionSize != fixedSize) {
|
||||
throw IllegalArgumentException("collection size is $collectionSize while fixed size of $fixedSize is required")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ annotation class CrcProtected
|
||||
@Target(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY)
|
||||
annotation class Unsigned
|
||||
|
||||
@SerialInfo
|
||||
@Target(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY)
|
||||
annotation class FixedSize(val size: Int)
|
||||
|
||||
open class InvalidFrameException(reason: String) : Exception(reason)
|
||||
class InvalidFrameHeaderException(reason: String = "Frame header does not match") : InvalidFrameException(reason)
|
||||
class InvalidFrameCRCException : InvalidFrameException("Checksum CRC32 failed")
|
||||
|
||||
@@ -5,7 +5,10 @@ import kotlinx.serialization.Serializable
|
||||
import net.sergeych.bintools.toDump
|
||||
import net.sergeych.bipack.*
|
||||
import kotlin.experimental.xor
|
||||
import kotlin.test.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
@Serializable
|
||||
data class Foobar1N(val bar: Int, val foo: Int = 117)
|
||||
@@ -114,7 +117,7 @@ class BipackEncoderTest {
|
||||
val u: UInt,
|
||||
@Unsigned
|
||||
val i: Int,
|
||||
val k: UInt = 3u,
|
||||
val k: Int = 3,
|
||||
)
|
||||
|
||||
@Test
|
||||
@@ -215,6 +218,28 @@ class BipackEncoderTest {
|
||||
// println(d.decodeFromBipack<Types1>())
|
||||
assertEquals(t1, t2)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Fixa(
|
||||
@FixedSize(5)
|
||||
val x: ByteArray
|
||||
)
|
||||
|
||||
@Test
|
||||
fun textFixed() {
|
||||
val x = byteArrayOf(1,2,3,4,5)
|
||||
//@Fixed(32)
|
||||
val y = Fixa(byteArrayOf(1,2,3,4,5))
|
||||
val d1 = BipackEncoder.encode(x)
|
||||
println(d1.toDump())
|
||||
assertEquals(6, d1.size)
|
||||
val d2 = BipackEncoder.encode(y)
|
||||
println(d2.toDump())
|
||||
assertEquals(5, d2.size)
|
||||
assertContentEquals(x, BipackDecoder.decode<ByteArray>(d1))
|
||||
assertContentEquals(x, BipackDecoder.decode<Fixa>(d2).x)
|
||||
}
|
||||
|
||||
// @Test
|
||||
@Test
|
||||
fun testMaps() {
|
||||
|
||||
Reference in new issue
Block a user