diff --git a/build.gradle.kts b/build.gradle.kts index 8077a43..ba367c4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { val serialization_version = "1.3.4" group = "net.sergeych" -version = "0.0.6" +version = "0.0.7" repositories { mavenCentral() diff --git a/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt b/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt index b97ed41..a12a409 100644 --- a/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt +++ b/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt @@ -16,6 +16,12 @@ interface DataSource { fun readByte(): Byte + /** + * true if there is no more data available and next read operation will surely + * throw EndOfData. Can return null if it is impossible to determine (for some + * async sources) + */ + fun isEnd(): Boolean? = null fun readUByte() = readByte().toUByte() @@ -50,6 +56,9 @@ fun ByteArray.toDataSource(): DataSource = var position = 0 private set + @Suppress("RedundantNullableReturnType") + override fun isEnd(): Boolean? = position == size + override fun readByte(): Byte = if (position < size) this@toDataSource[position++] else throw DataSource.EndOfData() @@ -65,6 +74,9 @@ fun UByteArray.toDataSource(): DataSource = var position = 0 private set + @Suppress("RedundantNullableReturnType") + override fun isEnd(): Boolean? = position == size + override fun readByte(): Byte = if (position < size) this@toDataSource[position++].toByte() else throw DataSource.EndOfData() diff --git a/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt b/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt index f22a068..f63c24c 100644 --- a/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt +++ b/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt @@ -57,7 +57,8 @@ class BipackDecoder( override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = input.readNumber().toInt() override fun decodeElementIndex(descriptor: SerialDescriptor): Int { - if (elementIndex >= elementsCount) return CompositeDecoder.DECODE_DONE + if (elementIndex >= elementsCount || input.isEnd() == true ) + return CompositeDecoder.DECODE_DONE nextIsUnsigned = false for (a in descriptor.getElementAnnotations(elementIndex)) { when (a) { diff --git a/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt b/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt index 366e6f5..7be187c 100644 --- a/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt +++ b/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt @@ -4,9 +4,16 @@ import kotlinx.serialization.SerialInfo /** * If this annotation is presented in some @Serializable class definition, its instances - * will be serialized with leading number of fields. This allows to extend class later + * will be serialized with the leading number of fields. This allows extending class later * providing new parameters __to the end of the class__ and _with default values__. * + * __IMPORTANT NOTE__. Since version 0.0.7 it's been also possible to use default values + * for non-serialized fields after the end-of-data. If the source reports it correctly, e.g. + * [net.sergeych.bintools.DataSource.isEnd] returns true, the unset fields are initialized + * with default value. This approach ___is not working when the loading instance is not the last + * in the deciding array!___, still it is useful to decode isolated objects. We recommend to + * use [Extendable] where needed and possible. + * * Whe deserializing such instances from previous version binaries, the new parameters * will get default values. * diff --git a/src/commonTest/kotlin/bipack/BipackEncoderTest.kt b/src/commonTest/kotlin/bipack/BipackEncoderTest.kt index 7cb24aa..01047e4 100644 --- a/src/commonTest/kotlin/bipack/BipackEncoderTest.kt +++ b/src/commonTest/kotlin/bipack/BipackEncoderTest.kt @@ -393,7 +393,16 @@ class BipackEncoderTest { assertEquals(xv, yv) println(xv) println(yv) - - } + + @Test + fun testStrangeUnpack() { + @Serializable + data class SFoo(val code: Int,val s1: String?=null,val s2: String?=null) + val z = BipackEncoder.encode(117) + println(z.toDump()) + val sf = BipackDecoder.decode(z) + println(sf) + } + } \ No newline at end of file