commonMain.ch.softappeal.yass2.serialize.binary.BinarySerializer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yass2-jvm Show documentation
Show all versions of yass2-jvm Show documentation
Yet Another Service Solution
package ch.softappeal.yass2.serialize.binary
import ch.softappeal.yass2.serialize.*
import kotlin.reflect.*
abstract class Encoder internal constructor(internal val type: KClass<*>) {
internal abstract fun write(writer: EncoderWriter, value: Any?)
internal abstract fun read(reader: EncoderReader): Any?
}
internal class EncoderId(val id: Int, val encoder: Encoder)
class EncoderWriter(internal val writer: Writer, private val serializer: BinarySerializer) {
fun writeWithId(value: Any?) {
val encoderId = when (value) {
null -> NullEncoderId
is List<*> -> ListEncoderId
else -> serializer.type2encoderId[value::class] ?: error("missing type '${value::class}'")
}
writer.writeVarInt(encoderId.id)
encoderId.encoder.write(this, value)
}
fun writeNoIdRequired(encoderId: Int, value: Any) = serializer.encoders[encoderId].write(this, value)
fun writeNoIdOptional(encoderId: Int, value: Any?) {
if (value == null) writer.writeByte(0) else {
writer.writeByte(1)
writeNoIdRequired(encoderId, value)
}
}
}
class EncoderReader(internal val reader: Reader, private val serializer: BinarySerializer) {
fun readWithId(): Any? = serializer.encoders[reader.readVarInt()].read(this)
fun readNoIdRequired(encoderId: Int): Any = serializer.encoders[encoderId].read(this)!!
fun readNoIdOptional(encoderId: Int): Any? {
if (reader.readByte().toInt() == 0) return null
return readNoIdRequired(encoderId)
}
}
private class NullType
private val NullEncoderId = EncoderId(0, object : Encoder(NullType::class) {
override fun write(writer: EncoderWriter, value: Any?) = Unit
override fun read(reader: EncoderReader): Any? = null
})
internal val ListEncoderId = EncoderId(1, object : Encoder(List::class) {
override fun write(writer: EncoderWriter, value: Any?) {
val list = value as List<*>
writer.writer.writeVarInt(list.size)
for (e in list) writer.writeWithId(e)
}
override fun read(reader: EncoderReader): MutableList<*> {
var length = reader.reader.readVarInt()
val list = ArrayList(minOf(length, 1000)) // prevents out-of-memory attack
while (length-- > 0) list.add(reader.readWithId())
return list
}
})
internal const val FirstEncoderId = 2
/** Supports the following types: `null`, [List], [BaseEncoder] and [ClassEncoder]. */
class BinarySerializer(encoders: List) : Serializer {
internal val encoders = (listOf(NullEncoderId.encoder, ListEncoderId.encoder) + encoders).toTypedArray()
internal val type2encoderId = HashMap, EncoderId>(this.encoders.size)
init {
this.encoders.withIndex().forEach { (id, encoder) ->
require(type2encoderId.put(encoder.type, EncoderId(id, encoder)) == null) {
"duplicated type '${encoder.type}'"
}
}
}
override fun write(writer: Writer, value: Any?) = EncoderWriter(writer, this).writeWithId(value)
override fun read(reader: Reader) = EncoderReader(reader, this).readWithId()
}
class ClassEncoder(
type: KClass,
private val writeProperties: (writer: EncoderWriter, instance: T) -> Unit,
private val readInstance: (reader: EncoderReader) -> T
) : Encoder(type) {
@Suppress("UNCHECKED_CAST")
override fun write(writer: EncoderWriter, value: Any?) = writeProperties(writer, value as T)
override fun read(reader: EncoderReader) = readInstance(reader)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy