Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How to implement KeyDispatchCodec like registry codec with codec factory? #85

Open
SettingDust opened this issue Dec 27, 2023 · 1 comment

Comments

@SettingDust
Copy link

SettingDust commented Dec 27, 2023

I will implement a KeyDispatchCodec for my custom registry with the Kotlin library codec factory.
How can I make the codec factory handle the polymorphic and get codec from the registry?

For example:
BuiltInRegistries.RECIPE_SERIALIZER.byNameCodec().dispatch(Recipe::getSerializer, RecipeSerializer::codec)

@SettingDust
Copy link
Author

Achieve with below. Open for advice

@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
open class DispatchedCodecSerializer<Out : Any, Type>(
    val targetCodec: Codec<Type>,
    val type: Function<Out, Type>,
    val codec: Function<Type, Codec<Out>>,
    private val serialName: String
) : KSerializer<Out> {
    override val descriptor =
        buildSerialDescriptor(serialName, PolymorphicKind.OPEN) {
            element("type", String.serializer().descriptor)
            element(
                "value",
                buildSerialDescriptor(
                    "DispatchedCodecSerializer<$serialName>",
                    SerialKind.CONTEXTUAL
                )
            )
        }

    override fun deserialize(decoder: Decoder): Out {
        if (decoder !is DynamicDecoder<*>) {
            throw UnsupportedOperationException(
                "Codec serializers can only be used in Dynamic serialization"
            )
        }

        val compositeDecoder = decoder.beginStructure(descriptor)

        var currentType: Type
        var elementCodec: Codec<Out>? = null
        var out: Out? = null
        while (true) {
            when (val index = compositeDecoder.decodeElementIndex(descriptor)) {
                0 -> {
                    currentType =
                        compositeDecoder.decodeSerializableElement(
                            descriptor,
                            0,
                            CodecSerializerAdapter(targetCodec, serialName)
                        )
                    elementCodec = codec.apply(currentType)
                }
                1 ->
                    out =
                        compositeDecoder.decodeSerializableElement(
                            descriptor,
                            1,
                            CodecSerializerAdapter(elementCodec!!, serialName)
                        )
                CompositeDecoder.DECODE_DONE -> break
                else -> error("Unexpected index: $index")
            }
        }

        decoder.endStructure(descriptor)
        return out!!
    }

    override fun serialize(encoder: Encoder, value: Out) {
        if (encoder !is DynamicEncoder<*>) {
            throw UnsupportedOperationException(
                "Codec serializers can only be used in Dynamic serialization"
            )
        }

        val compositeEncoder = encoder.beginStructure(descriptor)

        val currentType = type.apply(value)
        compositeEncoder.encodeSerializableElement(
            descriptor,
            0,
            CodecSerializerAdapter(targetCodec, serialName),
            currentType
        )
        val elementCodec = codec.apply(currentType)
        compositeEncoder.encodeSerializableElement(
            descriptor,
            1,
            CodecSerializerAdapter(elementCodec, serialName),
            value
        )

        encoder.endStructure(descriptor)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant