fixe #2 effective Instant binary representation (truncates to millis though)
This commit is contained in:
parent
d0f29ce06f
commit
ee20bfdee7
@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
kotlin("multiplatform") version "1.8.10"
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
kotlin("multiplatform") version "1.8.20"
|
||||
kotlin("plugin.serialization") version "1.8.20"
|
||||
id("org.jetbrains.dokka") version "1.6.0"
|
||||
`maven-publish`
|
||||
}
|
||||
@ -8,7 +8,7 @@ plugins {
|
||||
val serialization_version = "1.3.4"
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.0.2-SNAPSHOT"
|
||||
version = "0.0.3-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -68,6 +68,7 @@ kotlin {
|
||||
// this is actually a bug: we need only the core, but bare core causes strange errors
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
// api("net.sergeych:mp_stools:[1.3.3,)")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
|
34
src/commonMain/kotlin/net.sergeych.bintools/MotherPack.kt
Normal file
34
src/commonMain/kotlin/net.sergeych.bintools/MotherPack.kt
Normal file
@ -0,0 +1,34 @@
|
||||
package net.sergeych.bintools
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.serializer
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Experimental interface for packing and unpacking binary formats.
|
||||
* Initial support intended for BiPack and BOSS to make it fast replaceable.
|
||||
* Also, JSON text version with binary converter is presented by default.
|
||||
*/
|
||||
interface MotherPacker {
|
||||
fun <T>pack(type: KType, payload: T): ByteArray
|
||||
fun <T>unpack(type: KType,packed: ByteArray): T
|
||||
}
|
||||
|
||||
inline fun <reified T>MotherPacker.pack(payload: T) = pack(typeOf<T>(), payload)
|
||||
inline fun <reified T>MotherPacker.unpack(packed: ByteArray) = unpack<T>(typeOf<T>(), packed)
|
||||
|
||||
class JsonPacker : MotherPacker {
|
||||
override fun <T> pack(type: KType, payload: T): ByteArray {
|
||||
return Json.encodeToString(serializer(type), payload).encodeToByteArray()
|
||||
}
|
||||
|
||||
override fun <T> unpack(type: KType, packed: ByteArray): T {
|
||||
return Json.decodeFromString<T>(
|
||||
serializer(type) as KSerializer<T>,
|
||||
packed.decodeToString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.sergeych.bipack
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
@ -15,6 +16,7 @@ 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
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class BipackDecoder(
|
||||
val input: DataSource, var elementsCount: Int = 0, val isCollection: Boolean = false,
|
||||
val hasFixedSize: Boolean = false,
|
||||
@ -64,12 +66,18 @@ class BipackDecoder(
|
||||
return elementIndex++
|
||||
}
|
||||
|
||||
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
|
||||
return if( deserializer == Instant.serializer() )
|
||||
Instant.fromEpochMilliseconds(decodeLong()) as T
|
||||
else
|
||||
super.decodeSerializableValue(deserializer)
|
||||
}
|
||||
override fun decodeSequentially(): Boolean = isCollection
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
|
||||
val isCollection = descriptor.kind == StructureKind.LIST || descriptor.kind == StructureKind.MAP
|
||||
|
||||
var source = if (descriptor.annotations.any { it is CrcProtected })
|
||||
val source = if (descriptor.annotations.any { it is CrcProtected })
|
||||
CRC32Source(input)
|
||||
else
|
||||
input
|
||||
@ -119,6 +127,7 @@ class BipackDecoder(
|
||||
fun <T> decode(source: DataSource, deserializer: DeserializationStrategy<T>): T =
|
||||
BipackDecoder(source).decodeSerializableValue(deserializer)
|
||||
|
||||
@Suppress("unused")
|
||||
inline fun <reified T> decode(source: DataSource): T = decode(source, serializer())
|
||||
inline fun <reified T> decode(source: ByteArray): T =
|
||||
decode(source.toDataSource(), serializer())
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.sergeych.bipack
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.AbstractEncoder
|
||||
@ -76,6 +77,11 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
|
||||
if (value is Instant) encodeLong(value.toEpochMilliseconds())
|
||||
else super.encodeSerializableValue(serializer, value)
|
||||
}
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
|
||||
// frame protection should start before anything else:
|
||||
val sink = if (descriptor.annotations.any { it is CrcProtected })
|
||||
@ -115,6 +121,7 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
|
||||
ArrayDataSink().also { encode(serializer, value, it) }.toByteArray()
|
||||
|
||||
inline fun <reified T> encode(value: T) = encode(serializer(), value)
|
||||
@Suppress("unused")
|
||||
inline fun <reified T> encode(value: T, sink: DataSink) = encode(serializer(), value, sink)
|
||||
|
||||
}
|
||||
|
18
src/commonMain/kotlin/net.sergeych.bipack/MotherBipack.kt
Normal file
18
src/commonMain/kotlin/net.sergeych.bipack/MotherBipack.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package net.sergeych.bipack
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.serializer
|
||||
import net.sergeych.bintools.MotherPacker
|
||||
import net.sergeych.bintools.toDataSource
|
||||
import kotlin.reflect.KType
|
||||
|
||||
class MotherBipack : MotherPacker {
|
||||
override fun <T> pack(type: KType, payload: T): ByteArray {
|
||||
return BipackEncoder.encode(serializer(type), payload)
|
||||
}
|
||||
|
||||
override fun <T> unpack(type: KType, packed: ByteArray): T {
|
||||
return BipackDecoder.decode<T>(packed.toDataSource(),
|
||||
serializer(type) as KSerializer<T>)
|
||||
}
|
||||
}
|
28
src/commonTest/kotlin/bintools/JsonPackerTest.kt
Normal file
28
src/commonTest/kotlin/bintools/JsonPackerTest.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package bintools
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sergeych.bintools.JsonPacker
|
||||
import net.sergeych.bintools.pack
|
||||
import net.sergeych.bintools.unpack
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class JsonPackerTest {
|
||||
@Serializable
|
||||
data class FB1(val foo: Int,val bar: String)
|
||||
@Test
|
||||
fun testPackUnpack() {
|
||||
val mp = JsonPacker()
|
||||
println(mp.pack(mapOf("foo" to 42)).decodeToString())
|
||||
assertEquals("""{"foo":42}""", mp.pack(mapOf("foo" to 42)).decodeToString())
|
||||
val x = mp.unpack<FB1>("""{"foo":42, "bar": "foo"}""".encodeToByteArray())
|
||||
println(x)
|
||||
assertEquals(42, x.foo)
|
||||
assertEquals("foo", x.bar)
|
||||
|
||||
var nx: FB1? = null
|
||||
println(mp.pack(nx).decodeToString())
|
||||
assertNull(mp.unpack<FB1?>("null".encodeToByteArray()))
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package bipack
|
||||
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sergeych.bintools.encodeToHex
|
||||
@ -341,4 +343,12 @@ class BipackEncoderTest {
|
||||
assertEquals("00 00 00 01 00 00 00 02", BipackEncoder.encode(Foo(0x100000002)).encodeToHex())
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInstant() {
|
||||
val x = Clock.System.now()
|
||||
// println( BipackEncoder.encode(x).toDump() )
|
||||
val y = BipackDecoder.decode<Instant>(BipackEncoder.encode(x))
|
||||
assertEquals(x.toEpochMilliseconds(), y.toEpochMilliseconds())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user