From 4281f74d832d73cc859660aa2f4bc758cd4f5eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Mon, 13 Sep 2021 23:39:12 +0200 Subject: [PATCH] feat: add strict type mode This closes #18 --- CHANGELOG.md | 2 ++ .../MsgPackConfiguration.kt | 7 +++- .../internal/MsgPackDecoder.kt | 12 +++---- .../internal/MsgUnpacker.kt | 32 +++++++++---------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a13ec6d..1739619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. This change - Upgraded kotlinx-serialization version to 1.2.2 - Added support for timestamp extension ([#10][i10]) - Added configuration for raw (old str) type compatibility ([#12][i12]) +- Added configuration for strict type mode ([#18][i18]) ### Fixed - Bug with failing to decode extension types with variable data size @@ -47,4 +48,5 @@ All notable changes to this project will be documented in this file. This change [i12]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/12 [i13]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/13 [i14]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/14 +[i18]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/18 [p40]: https://github.com/esensar/kotlinx-serialization-msgpack/pull/40 diff --git a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/MsgPackConfiguration.kt b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/MsgPackConfiguration.kt index 35b4496..eaecfc0 100644 --- a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/MsgPackConfiguration.kt +++ b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/MsgPackConfiguration.kt @@ -14,7 +14,12 @@ data class MsgPackConfiguration( * Enables backwards compatibility with MsgPack 1.0 spec which has raw type instead of string * Disables use of bin types and str8 types in serialization and support deserializing string types as bytearrays */ - val rawCompatibility: Boolean = false + val rawCompatibility: Boolean = false, + /** + * Enables strict mode type, which forces exact types when deserializing + * (not allowing INT16 to be deserialized in place of Int for example) + */ + val strictTypes: Boolean = false ) { companion object { @JvmStatic diff --git a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgPackDecoder.kt b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgPackDecoder.kt index 55cabf5..66d87b6 100644 --- a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgPackDecoder.kt +++ b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgPackDecoder.kt @@ -47,27 +47,27 @@ internal class BasicMsgPackDecoder( } override fun decodeByte(): Byte { - return msgUnpacker.unpackByte() + return msgUnpacker.unpackByte(configuration.strictTypes) } override fun decodeShort(): Short { - return msgUnpacker.unpackShort() + return msgUnpacker.unpackShort(configuration.strictTypes) } override fun decodeInt(): Int { - return msgUnpacker.unpackInt() + return msgUnpacker.unpackInt(configuration.strictTypes) } override fun decodeLong(): Long { - return msgUnpacker.unpackLong() + return msgUnpacker.unpackLong(configuration.strictTypes) } override fun decodeFloat(): Float { - return msgUnpacker.unpackFloat() + return msgUnpacker.unpackFloat(configuration.strictTypes) } override fun decodeDouble(): Double { - return msgUnpacker.unpackDouble() + return msgUnpacker.unpackDouble(configuration.strictTypes) } override fun decodeString(): String { diff --git a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgUnpacker.kt b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgUnpacker.kt index 5f79a28..01aa03e 100644 --- a/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgUnpacker.kt +++ b/serialization-msgpack/src/commonMain/kotlin/com.ensarsarajcic.kotlinx.serialization.msgpack/internal/MsgUnpacker.kt @@ -7,12 +7,12 @@ import com.ensarsarajcic.kotlinx.serialization.msgpack.utils.joinToNumber internal interface MsgUnpacker { fun unpackNull() fun unpackBoolean(): Boolean - fun unpackByte(): Byte - fun unpackShort(): Short - fun unpackInt(): Int - fun unpackLong(): Long - fun unpackFloat(): Float - fun unpackDouble(): Double + fun unpackByte(strict: Boolean = false): Byte + fun unpackShort(strict: Boolean = false): Short + fun unpackInt(strict: Boolean = false): Int + fun unpackLong(strict: Boolean = false): Long + fun unpackFloat(strict: Boolean = false): Float + fun unpackDouble(strict: Boolean = false): Double fun unpackString(): String fun unpackByteArray(): ByteArray } @@ -31,7 +31,7 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) } } - override fun unpackByte(): Byte { + override fun unpackByte(strict: Boolean): Byte { // Check is it a single byte value val next = dataBuffer.requireNextByte() return when { @@ -42,7 +42,7 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) } } - override fun unpackShort(): Short { + override fun unpackShort(strict: Boolean): Short { val next = dataBuffer.peek() return when { MsgPackType.Int.isShort(next) -> { @@ -53,11 +53,11 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) dataBuffer.skip(1) (dataBuffer.requireNextByte().toInt() and 0xff).toShort() } - else -> unpackByte().toShort() + else -> if (strict) TODO("Strict type error") else unpackByte(strict).toShort() } } - override fun unpackInt(): Int { + override fun unpackInt(strict: Boolean): Int { val next = dataBuffer.peek() return when { MsgPackType.Int.isInt(next) -> { @@ -68,11 +68,11 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) dataBuffer.skip(1) dataBuffer.takeNext(2).joinToNumber() } - else -> unpackShort().toInt() + else -> if (strict) TODO("Strict type error") else unpackShort(strict).toInt() } } - override fun unpackLong(): Long { + override fun unpackLong(strict: Boolean): Long { val next = dataBuffer.peek() return when { MsgPackType.Int.isLong(next) -> { @@ -83,11 +83,11 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) dataBuffer.skip(1) dataBuffer.takeNext(4).joinToNumber() } - else -> unpackInt().toLong() + else -> if (strict) TODO("Strict type error") else unpackInt(strict).toLong() } } - override fun unpackFloat(): Float { + override fun unpackFloat(strict: Boolean): Float { return when (dataBuffer.peek()) { MsgPackType.Float.FLOAT -> { dataBuffer.skip(1) @@ -97,13 +97,13 @@ internal class BasicMsgUnpacker(private val dataBuffer: MsgPackDataInputBuffer) } } - override fun unpackDouble(): Double { + override fun unpackDouble(strict: Boolean): Double { return when (dataBuffer.peek()) { MsgPackType.Float.DOUBLE -> { dataBuffer.skip(1) Double.fromBits(dataBuffer.takeNext(8).joinToNumber()) } - MsgPackType.Float.FLOAT -> unpackFloat().toDouble() + MsgPackType.Float.FLOAT -> if (strict) TODO("Strict type error") else unpackFloat(strict).toDouble() else -> TODO("Add a more descriptive error when wrong type is found!") } }