Skip to content

Commit

Permalink
Merge pull request #74 from esensar/release/0.5.0
Browse files Browse the repository at this point in the history
Release/0.5.0
  • Loading branch information
esensar authored Dec 22, 2021
2 parents 5d704d6 + 86c6ef7 commit 86a7914
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 55 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. This change

## [Unreleased]

## [0.5.0] - 2021-12-22
- More descriptive errors ([#21][i21])

## [0.4.4] - 2021-12-20
- Added support for ignoring unknown keys ([#69][i69])

Expand Down Expand Up @@ -82,7 +85,7 @@ MsgPack.default.encodeToByteArray(...)
- `MsgPackDynamicSerializer` as placeholder for future [contextual serializer](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#contextual-serialization)
- Full implementation of msgpack spec excluding extension types and bin format family

[Unreleased]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.4.4...main
[Unreleased]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.5.0...main
[0.2.0]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.1.0...0.2.0
[0.2.1]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.2.0...0.2.1
[0.3.0]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.2.1...0.3.0
Expand All @@ -91,6 +94,7 @@ MsgPack.default.encodeToByteArray(...)
[0.4.2]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.4.1...0.4.2
[0.4.3]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.4.2...0.4.3
[0.4.4]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.4.3...0.4.4
[0.5.0]: https://github.com/esensar/kotlinx-serialization-msgpack/compare/0.4.4...0.5.0
[i6]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/6
[i9]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/9
[i10]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/10
Expand All @@ -102,6 +106,7 @@ MsgPack.default.encodeToByteArray(...)
[i18]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/18
[i19]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/19
[i20]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/20
[i21]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/21
[i55]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/55
[i57]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/57
[i60]: https://github.com/esensar/kotlinx-serialization-msgpack/issues/60
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ org.gradle.parallel=true
org.gradle.caching=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1g

version=0.4.4
version=0.5.0
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import com.ensarsarajcic.kotlinx.serialization.msgpack.extensions.MsgPackTimesta
import kotlinx.datetime.Instant

sealed class BaseMsgPackDatetimeSerializer(private val outputType: Byte) : BaseMsgPackExtensionSerializer<Instant>() {

init {
require(outputType in 0..2) { "Output type can only take values from 0 to 2 inclusive" }
}

private val timestampSerializer = MsgPackTimestampExtensionSerializer
override fun deserialize(extension: MsgPackExtension): Instant {
return when (val timestamp = timestampSerializer.deserialize(extension)) {
Expand All @@ -27,7 +32,7 @@ sealed class BaseMsgPackDatetimeSerializer(private val outputType: Byte) : BaseM
2.toByte() -> {
MsgPackTimestamp.T92(extension.epochSeconds, extension.nanosecondsOfSecond.toLong())
}
else -> TODO("Needs more info")
else -> throw AssertionError()
}
return timestampSerializer.serialize(timestamp)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack.unsigned

import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
import com.ensarsarajcic.kotlinx.serialization.msgpack.internal.InlineDecoderHelper
import com.ensarsarajcic.kotlinx.serialization.msgpack.internal.InlineEncoderHelper
import com.ensarsarajcic.kotlinx.serialization.msgpack.unsigned.utils.joinToNumber
Expand Down Expand Up @@ -58,7 +59,7 @@ class UByteDecoder(private val decoderHelper: InlineDecoderHelper) : AbstractDec

override fun decodeByte(): Byte {
val type = decoderHelper.inputBuffer.requireNextByte()
if (type != UnsignedTypes.UINT8) throw TODO("BAD TYPE")
if (type != UnsignedTypes.UINT8) throw MsgPackSerializationException.deserialization(decoderHelper.inputBuffer, "Expected UINT8 type, but found $type")
return decoderHelper.inputBuffer.requireNextByte()
}
}
Expand All @@ -70,7 +71,7 @@ class UShortDecoder(private val decoderHelper: InlineDecoderHelper) : AbstractDe

override fun decodeShort(): Short {
val type = decoderHelper.inputBuffer.requireNextByte()
if (type != UnsignedTypes.UINT16) throw TODO("BAD TYPE")
if (type != UnsignedTypes.UINT16) throw MsgPackSerializationException.deserialization(decoderHelper.inputBuffer, "Expected UINT16 type, but found $type")
return decoderHelper.inputBuffer.takeNext(2).joinToNumber()
}
}
Expand All @@ -82,7 +83,7 @@ class UIntDecoder(private val decoderHelper: InlineDecoderHelper) : AbstractDeco

override fun decodeInt(): Int {
val type = decoderHelper.inputBuffer.requireNextByte()
if (type != UnsignedTypes.UINT32) throw TODO("BAD TYPE")
if (type != UnsignedTypes.UINT32) throw MsgPackSerializationException.deserialization(decoderHelper.inputBuffer, "Expected UINT32 type, but found $type")
return decoderHelper.inputBuffer.takeNext(4).joinToNumber()
}
}
Expand All @@ -94,7 +95,7 @@ class ULongDecoder(private val decoderHelper: InlineDecoderHelper) : AbstractDec

override fun decodeLong(): Long {
val type = decoderHelper.inputBuffer.requireNextByte()
if (type != UnsignedTypes.UINT64) throw TODO("BAD TYPE")
if (type != UnsignedTypes.UINT64) throw MsgPackSerializationException.deserialization(decoderHelper.inputBuffer, "Expected UINT64 type, but found $type")
return decoderHelper.inputBuffer.takeNext(8).joinToNumber()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack

import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
import com.ensarsarajcic.kotlinx.serialization.msgpack.extensions.DynamicMsgPackExtensionSerializer
import com.ensarsarajcic.kotlinx.serialization.msgpack.internal.MsgPackTypeDecoder
import com.ensarsarajcic.kotlinx.serialization.msgpack.types.MsgPackType
Expand Down Expand Up @@ -39,7 +40,7 @@ open class MsgPackNullableDynamicSerializer(
) : KSerializer<Any?> {
companion object Default : MsgPackNullableDynamicSerializer(DynamicMsgPackExtensionSerializer)
final override fun deserialize(decoder: Decoder): Any? {
if (decoder !is MsgPackTypeDecoder) TODO("Unsupported decoder!")
if (decoder !is MsgPackTypeDecoder) throw MsgPackSerializationException.dynamicSerializationError("Unsupported decoder: $decoder")
val type = decoder.peekNextType()
return when {
type == MsgPackType.NULL -> decoder.decodeNull()
Expand Down Expand Up @@ -78,7 +79,7 @@ open class MsgPackNullableDynamicSerializer(
MsgPackType.Array.isArray(type) -> ListSerializer(this).deserialize(decoder)
MsgPackType.Map.isMap(type) -> MapSerializer(this, this).deserialize(decoder)
MsgPackType.Ext.isExt(type) -> dynamicMsgPackExtensionSerializer.deserialize(decoder)
else -> TODO("Missing decoder for type")
else -> throw MsgPackSerializationException.dynamicSerializationError("Missing decoder for type: $type")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions

import com.ensarsarajcic.kotlinx.serialization.msgpack.extensions.MsgPackExtension
import com.ensarsarajcic.kotlinx.serialization.msgpack.stream.MsgPackDataBuffer
import com.ensarsarajcic.kotlinx.serialization.msgpack.stream.MsgPackDataInputBuffer
import com.ensarsarajcic.kotlinx.serialization.msgpack.stream.MsgPackDataOutputBuffer
import kotlinx.serialization.SerializationException

private fun ByteArray.toHex() = this.joinToString(separator = "") { it.toHex() }
private fun Byte.toHex() = toInt().and(0xff).toString(16).padStart(2, '0')
private fun MsgPackExtension.toInfoString() = "{type = $type, extTypeId = $extTypeId, data = ${data.toHex()}}"

class MsgPackSerializationException private constructor(
override val message: String
) : SerializationException() {
companion object {
private fun MsgPackDataInputBuffer.locationInfo() =
toByteArray().toList().let {
"""
${it.subList(0, index).toByteArray().toHex()}[${peekSafely()}]${it.subList((index + 1).coerceAtMost(it.size), it.size)}
${(0 until index).joinToString(separator = "") { " " }}} ^^ ${((index + 1) until it.size).joinToString(separator = "") { " " }}
""".trimIndent()
}

private fun MsgPackDataOutputBuffer.locationInfo() =
"Written so far: ${toByteArray().toHex()}\nSize: ${toByteArray().size} bytes"

private fun coreSerialization(buffer: MsgPackDataBuffer, locationInfo: String, reason: String? = null): MsgPackSerializationException {
return MsgPackSerializationException(
"MsgPack Serialization failure while serializing: ${buffer.toByteArray().toHex()}\nReason: $reason\nCurrent position:\n\n$locationInfo"
)
}

private fun extensionSerialization(extension: MsgPackExtension, reason: String? = null): MsgPackSerializationException {
return MsgPackSerializationException(
"MsgPack Serialization failure while serializing: ${extension.toInfoString()}\nReason: $reason"
)
}

fun deserialization(buffer: MsgPackDataInputBuffer, reason: String? = null): MsgPackSerializationException {
return coreSerialization(buffer, buffer.locationInfo(), reason)
}

fun serialization(buffer: MsgPackDataOutputBuffer, reason: String? = null): MsgPackSerializationException {
return coreSerialization(buffer, buffer.locationInfo(), reason)
}

fun extensionSerializationWrongType(extension: MsgPackExtension, expectedType: Byte, foundType: Byte): MsgPackSerializationException {
return extensionSerialization(extension, "Expected extension type ${expectedType.toHex()} but found ${foundType.toHex()}. Deserialized extension: $extension")
}

fun extensionDeserializationWrongType(extension: MsgPackExtension, expectedType: Byte, foundType: Byte): MsgPackSerializationException {
return extensionSerialization(extension, "Expected extension type ${expectedType.toHex()} but found ${foundType.toHex()}. Serialized extension: $extension")
}

fun genericExtensionError(extension: MsgPackExtension, reason: String? = null): MsgPackSerializationException {
return extensionSerialization(extension, reason)
}

fun packingError(reason: String? = null): MsgPackSerializationException {
return MsgPackSerializationException("MsgPack Serialization failure while packing value! Reason: $reason")
}

fun unpackingError(reason: String? = null): MsgPackSerializationException {
return MsgPackSerializationException("MsgPack Serialization failure while unpacking value! Reason: $reason")
}

fun dynamicSerializationError(reason: String? = null): MsgPackSerializationException {
return MsgPackSerializationException("MsgPack Dynamic Serialization failure! Reason: $reason")
}

fun strictTypeError(buffer: MsgPackDataInputBuffer, expectedType: String, foundType: String): MsgPackSerializationException {
return deserialization(buffer, "Strict type error! Expected type $expectedType, but found $foundType")
}

fun overflowError(buffer: MsgPackDataInputBuffer): MsgPackSerializationException {
return deserialization(buffer, "Overflow error!")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack.extensions

import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
Expand All @@ -11,7 +12,7 @@ abstract class BaseMsgPackExtensionSerializer<T> : KSerializer<T> {
override fun deserialize(decoder: Decoder): T {
val extension = decoder.decodeSerializableValue(serializer)
if (checkTypeId && extension.extTypeId != extTypeId) {
throw TODO("Add more info")
throw MsgPackSerializationException.extensionDeserializationWrongType(extension, extTypeId, extension.extTypeId)
}
return deserialize(extension)
}
Expand All @@ -21,7 +22,7 @@ abstract class BaseMsgPackExtensionSerializer<T> : KSerializer<T> {
override fun serialize(encoder: Encoder, value: T) {
val extension = serialize(value)
if (checkTypeId && extension.extTypeId != extTypeId) {
throw TODO("Add more info")
throw MsgPackSerializationException.extensionSerializationWrongType(extension, extTypeId, extension.extTypeId)
}
encoder.encodeSerializableValue(serializer, serialize(value))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack.extensions

import kotlinx.serialization.SerializationException
import kotlin.reflect.KClass

open class DynamicMsgPackExtensionSerializer : BaseMsgPackExtensionSerializer<Any?>() {
Expand Down Expand Up @@ -52,7 +53,7 @@ open class DynamicMsgPackExtensionSerializer : BaseMsgPackExtensionSerializer<An
return serializer.serialize(extension)
}
}
throw TODO("missing serializer")
throw SerializationException("Missing serializer for extension: $extension")
}

final override val extTypeId: Byte = 0x00
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack.extensions

import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
import com.ensarsarajcic.kotlinx.serialization.msgpack.utils.joinToNumber
import com.ensarsarajcic.kotlinx.serialization.msgpack.utils.splitToByteArray
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -59,7 +60,7 @@ open class MsgPackTimestampExtensionSerializer :
MsgPackExtension.Type.EXT8 -> {
// Working with Timestamp 96
if (extension.data.size != TIMESTAMP_96_DATA_SIZE) {
throw TODO("Needs more info")
throw MsgPackSerializationException.genericExtensionError(extension, "Error when parsing datetime. Expected data size of $TIMESTAMP_96_DATA_SIZE, but found ${extension.data.size}")
}
val nanoseconds = extension.data
.take(4)
Expand All @@ -71,7 +72,7 @@ open class MsgPackTimestampExtensionSerializer :
.joinToNumber<Long>()
return MsgPackTimestamp.T92(seconds, nanoseconds)
}
else -> TODO("Needs more info")
else -> throw MsgPackSerializationException.genericExtensionError(extension, "Unsupported extension type for timestamp: ${extension.type}")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.ensarsarajcic.kotlinx.serialization.msgpack.internal

import com.ensarsarajcic.kotlinx.serialization.msgpack.MsgPackConfiguration
import com.ensarsarajcic.kotlinx.serialization.msgpack.MsgPackNullableDynamicSerializer
import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
import com.ensarsarajcic.kotlinx.serialization.msgpack.stream.MsgPackDataInputBuffer
import com.ensarsarajcic.kotlinx.serialization.msgpack.types.MsgPackType
import com.ensarsarajcic.kotlinx.serialization.msgpack.utils.joinToNumber
Expand Down Expand Up @@ -127,7 +128,7 @@ internal class BasicMsgPackDecoder(
if (configuration.preventOverflows) {
val number = dataBuffer.takeNext(4).joinToNumber<Long>()
if (number !in Int.MIN_VALUE..Int.MAX_VALUE) {
throw TODO("Overflow error")
throw MsgPackSerializationException.overflowError(dataBuffer)
} else {
number.toInt()
}
Expand All @@ -136,7 +137,7 @@ internal class BasicMsgPackDecoder(
}
}
else -> {
throw TODO("Add a more descriptive error when wrong type is found!")
throw MsgPackSerializationException.deserialization(dataBuffer, "Unknown array type: $next")
}
}

Expand All @@ -148,7 +149,7 @@ internal class BasicMsgPackDecoder(
if (configuration.preventOverflows) {
val number = dataBuffer.takeNext(4).joinToNumber<Long>()
if (number !in Int.MIN_VALUE..Int.MAX_VALUE) {
throw TODO("Overflow error")
throw MsgPackSerializationException.overflowError(dataBuffer)
} else {
number.toInt()
}
Expand All @@ -157,12 +158,12 @@ internal class BasicMsgPackDecoder(
}
}
else -> {
throw TODO("Add a more descriptive error when wrong type is found!")
throw MsgPackSerializationException.deserialization(dataBuffer, "Unknown map type: $next")
}
}

else -> {
TODO("Unsupported collection")
throw MsgPackSerializationException.deserialization(dataBuffer, "Unsupported collection: ${descriptor.kind}")
}
}
}
Expand All @@ -181,9 +182,8 @@ internal class BasicMsgPackDecoder(
return ExtensionTypeDecoder(this)
}
// Handle extension types as arrays
decodeCollectionSize(descriptor)
return ClassMsgPackDecoder(this)
// TODO compare with descriptor.elementsCount
val size = decodeCollectionSize(descriptor)
return ClassMsgPackDecoder(this, size)
}
return this
}
Expand All @@ -200,14 +200,15 @@ internal class MsgPackDecoder(
}

internal class ClassMsgPackDecoder(
private val basicMsgPackDecoder: BasicMsgPackDecoder
private val basicMsgPackDecoder: BasicMsgPackDecoder,
private val size: Int
) : Decoder by basicMsgPackDecoder, CompositeDecoder by basicMsgPackDecoder, MsgPackTypeDecoder by basicMsgPackDecoder {
override val serializersModule: SerializersModule = basicMsgPackDecoder.serializersModule

private var decodedElements = 0

override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
if (decodedElements >= descriptor.elementsCount) return CompositeDecoder.DECODE_DONE
if (decodedElements >= size) return CompositeDecoder.DECODE_DONE
val result = basicMsgPackDecoder.decodeElementIndex(descriptor)
if (result != CompositeDecoder.DECODE_DONE) decodedElements++
return result
Expand All @@ -234,7 +235,7 @@ internal class ExtensionTypeDecoder(
val byte = dataBuffer.requireNextByte()
bytesRead++
if (!MsgPackType.Ext.isExt(byte)) {
throw TODO("Unexpected byte")
throw MsgPackSerializationException.deserialization(dataBuffer, "Unexpected byte: $byte. Expected extension type byte!")
}
type = byte
if (MsgPackType.Ext.SIZES.containsKey(type)) {
Expand All @@ -254,7 +255,7 @@ internal class ExtensionTypeDecoder(
typeId = byte
typeId!!
} else {
throw TODO("Handle?")
throw AssertionError()
}
}
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
Expand Down
Loading

0 comments on commit 86a7914

Please sign in to comment.