refs #35 serializatino framework refactored: implementation put in open methods of Obj/ObjClass for flexibility

This commit is contained in:
sergeych committed 2025-07-19 12:28:14 +03:00
1 parent 6ab438b1f6
commit a9f65bdbe3
20 files changed
+340 -203

No files matched your search

@@ -1,14 +1,23 @@
package net.sergeych.lynon
import kotlinx.datetime.Instant
import net.sergeych.lyng.Scope
import net.sergeych.lyng.obj.*
import net.sergeych.lyng.obj.Obj
import net.sergeych.lyng.obj.ObjClass
open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSettings.default) {
val cache = mutableListOf<Obj>()
fun getBitsAsInt(bitsSize: Int): Int {
return bin.getBits(bitsSize).toInt()
}
inline fun decodeCached(f: LynonDecoder.() -> Obj): Obj {
fun unpackUnsignedInt(): Int = bin.unpackUnsigned().toInt()
fun decompress() = bin.decompress()
val cache = mutableListOf<Any>()
inline fun <T : Any>decodeCached(f: LynonDecoder.() -> T): T {
return if (bin.getBit() == 0) {
// unpack and cache
f().also {
@@ -20,46 +29,19 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
val id = bin.getBitsOrNull(size)?.toInt()
?: throw RuntimeException("Invalid object id: unexpected end of stream")
if (id >= cache.size) throw RuntimeException("Invalid object id: $id should be in 0..<${cache.size}")
cache[id]
@Suppress("UNCHECKED_CAST")
cache[id] as T
}
}
fun decodeAny(scope: Scope): Obj = decodeCached {
suspend fun decodeAny(scope: Scope): Obj = decodeCached {
val type = LynonType.entries[bin.getBits(4).toInt()]
return when (type) {
LynonType.Null -> ObjNull
LynonType.Int0 -> ObjInt.Zero
LynonType.IntPositive -> ObjInt(bin.unpackUnsigned().toLong())
LynonType.IntNegative -> ObjInt(-bin.unpackUnsigned().toLong())
LynonType.Bool -> ObjBool(bin.getBit() == 1)
LynonType.Real -> ObjReal(bin.unpackDouble())
LynonType.Instant -> {
val mode = LynonSettings.InstantTruncateMode.entries[bin.getBits(2).toInt()]
when (mode) {
LynonSettings.InstantTruncateMode.Microsecond -> ObjInstant(
Instant.fromEpochSeconds(
bin.unpackSigned(), bin.unpackUnsigned().toInt() * 1000
)
)
LynonSettings.InstantTruncateMode.Millisecond -> ObjInstant(
Instant.fromEpochMilliseconds(
bin.unpackSigned()
)
)
LynonSettings.InstantTruncateMode.Second -> ObjInstant(
Instant.fromEpochSeconds(bin.unpackSigned())
)
}
}
else -> {
scope.raiseNotImplemented("lynon type $type")
}
}
type.objClass.deserialize(scope, this, type)
}
fun unpackObject(scope: Scope, type: ObjClass): Obj {
return decodeCached { type.deserialize(scope, this) }
// todo: rewrite/remove?
suspend fun unpackObject(scope: Scope, type: ObjClass): Obj {
return decodeCached { type.deserialize(scope, this, null) }
}
fun unpackBinaryData(): ByteArray = bin.decompress()
@@ -79,4 +61,8 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
return bin.unpackSigned()
}
fun unpackUnsigned(): ULong {
return bin.unpackUnsigned()
}
}