All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.pro.felixo.protobuf.serialization.EncodingSchema.kt Maven / Gradle / Ivy

The newest version!
package pro.felixo.protobuf.serialization

import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule
import pro.felixo.protobuf.EnumValue
import pro.felixo.protobuf.FieldNumber
import pro.felixo.protobuf.FieldRule
import pro.felixo.protobuf.Identifier
import pro.felixo.protobuf.serialization.encoding.FieldEncoding
import pro.felixo.protobuf.serialization.encoding.HybridDecoder
import pro.felixo.protobuf.serialization.encoding.HybridEncoder
import pro.felixo.protobuf.serialization.encoding.varInt
import pro.felixo.protobuf.serialization.generation.encodingSchema
import pro.felixo.protobuf.serialization.util.simpleTypeName
import pro.felixo.protobuf.wire.WireBuffer
import pro.felixo.protobuf.wire.WireValue

/**
 * A [BinaryFormat] for encoding and decoding protobuf messages. Applications should obtain instances of this class
 * using the [encodingSchema] function.
 */
class EncodingSchema(
    override val serializersModule: SerializersModule,
    val types: Map
) : BinaryFormat {

    override fun  encodeToByteArray(serializer: SerializationStrategy, value: T): ByteArray {
        val output = WireBuffer()
        val simpleTypeName = simpleTypeName(serializer.descriptor)
        val message = types[simpleTypeName] as? Message ?: error("Not a message type: $simpleTypeName")
        val encoder = message.encoder(output, null, true)
        serializer.serialize(encoder, value)
        return output.getBytes()
    }

    override fun  decodeFromByteArray(deserializer: DeserializationStrategy, bytes: ByteArray): T {
        val simpleTypeName = simpleTypeName(deserializer.descriptor)
        val message = types[simpleTypeName] as? Message ?: error("Not a message type: $simpleTypeName")
        val decoder = message.decoder(listOf(WireValue.Len(WireBuffer(bytes))))
        return deserializer.deserialize(decoder)
    }
}

sealed class Type {
    abstract val name: Identifier
}

class Message(
    override val name: Identifier,
    val members: List = emptyList(),
    val nestedTypes: List = emptyList(),
    val encoder: (output: WireBuffer, fieldNumber: FieldNumber?, encodeZeroValue: Boolean) -> HybridEncoder,
    val decoder: (value: List) -> HybridDecoder
) : Type() {
    val fields: List =
        members.filterIsInstance() + members.filterIsInstance().flatMap { it.fields }
}

sealed interface Member {
    val name: Identifier
}

class Field(
    override val name: Identifier,
    val encoding: FieldEncoding,
    val number: FieldNumber,
    val rule: FieldRule = FieldRule.Singular,
    val encoder: ((WireBuffer) -> Encoder),
    val decoder: ((List) -> Decoder)
) : Member

class OneOf(
    override val name: Identifier,
    val fields: List
) : Member

class Enum(
    override val name: Identifier,
    val values: List
) : Type() {
    private val numberByElementIndex: List by lazy { values.map { it.number } }
    private val elementIndexByNumber = numberByElementIndex.withIndex().associate { it.value to it.index }
    private val defaultElementIndex: Int = numberByElementIndex.indexOf(0)

    fun decode(number: Int): Int = elementIndexByNumber[number] ?: defaultElementIndex
    fun encode(elementIndex: Int, encodeZeroValue: Boolean): WireValue.VarInt? = varInt(
        numberByElementIndex[elementIndex],
        encodeZeroValue
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy