facet_generate 0.16.0

Generate Swift, Kotlin and TypeScript from types annotated with `#[derive(Facet)]`
Documentation
package com.example

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*

@Serializable @Parcelize data class Struct(val field1: String, val field2: UInt) : Parcelable

@Parcelize
@Serializable
enum class UnitEnum : Parcelable {
    @SerialName("VariantA") VARIANT_A,
    @SerialName("VariantB") VARIANT_B,
    @SerialName("VariantC") VARIANT_C;

    val serialName: String
        get() = javaClass.getDeclaredField(name).getAnnotation(SerialName::class.java)!!.value
}

@Parcelize
@Serializable(with = ExternallyTaggedEnum.Serializer::class)
sealed interface ExternallyTaggedEnum : Parcelable {
    @Serializable data class TupleVariant(val value: String) : ExternallyTaggedEnum

    @Serializable data class StructVariant(val field: String) : ExternallyTaggedEnum

    object Serializer : KSerializer<ExternallyTaggedEnum> {
        override val descriptor =
                buildClassSerialDescriptor("ExternallyTaggedEnum") {
                    element<TupleVariant>("TupleVariant", isOptional = true)
                    element<StructVariant>("StructVariant", isOptional = true)
                }

        override fun serialize(encoder: Encoder, value: ExternallyTaggedEnum) {
            encoder.encodeStructure(descriptor) {
                when (value) {
                    is TupleVariant ->
                            encodeSerializableElement(
                                    descriptor,
                                    0,
                                    String.serializer(),
                                    value.value
                            )
                    is StructVariant ->
                            encodeSerializableElement(
                                    descriptor,
                                    1,
                                    StructVariant.serializer(),
                                    value
                            )
                }
            }
        }

        override fun deserialize(decoder: Decoder): ExternallyTaggedEnum {
            return decoder.decodeStructure(descriptor) {
                when (val index = decodeElementIndex(descriptor)) {
                    0 -> {
                        val value = decodeSerializableElement(descriptor, 0, String.serializer())
                        return@decodeStructure TupleVariant(value)
                    }
                    1 -> {
                        return@decodeStructure decodeSerializableElement(
                                descriptor,
                                1,
                                StructVariant.serializer()
                        )
                    }
                    else -> throw Exception("Unknown enum variant $index for ExternallyTaggedEnum")
                }
            }
        }
    }
}

@Parcelize
@Serializable(with = InternallyTaggedEnum.Serializer::class)
@JsonClassDiscriminator("type")
sealed interface InternallyTaggedEnum : Parcelable {
    @Serializable @SerialName("UnitVariant") data object UnitVariant : InternallyTaggedEnum

    @Serializable
    @SerialName("TupleVariant")
    data class TupleVariant(val value: String) : InternallyTaggedEnum

    @Serializable
    @SerialName("StructVariant")
    data class StructVariant(val field: String) : InternallyTaggedEnum

    object Serializer : KSerializer<InternallyTaggedEnum> {
        override val descriptor =
                buildClassSerialDescriptor("InternallyTaggedEnum") {
                    element<UnitVariant>("UnitVariant", isOptional = true)
                    element<TupleVariant>("TupleVariant", isOptional = true)
                    element<StructVariant>("StructVariant", isOptional = true)
                }

        override fun serialize(encoder: Encoder, value: InternallyTaggedEnum) {
            require(encoder is JsonEncoder)
            when (value) {
                is UnitVariant -> {
                    val base =
                            mutableMapOf<String, JsonElement>(
                                    "type" to JsonPrimitive("UnitVariant")
                            )
                    val element = JsonObject(base)
                    encoder.encodeJsonElement(element)
                }
                is TupleVariant -> {
                    val content =
                            encoder.json.encodeToJsonElement(String.serializer(), value.value) as
                                    JsonObject
                    val base =
                            mutableMapOf<String, JsonElement>(
                                    "type" to JsonPrimitive("TupleVariant")
                            )
                    val element = JsonObject(base.apply { putAll(content.toMap()) })
                    encoder.encodeJsonElement(element)
                }
                is StructVariant -> {
                    val content =
                            encoder.json.encodeToJsonElement(StructVariant.serializer(), value) as
                                    JsonObject
                    val base =
                            mutableMapOf<String, JsonElement>(
                                    "type" to JsonPrimitive("StructVariant")
                            )
                    val element = JsonObject(base.apply { putAll(content.toMap()) })
                    encoder.encodeJsonElement(element)
                }
            }
        }

        override fun deserialize(decoder: Decoder): InternallyTaggedEnum {
            require(decoder is JsonDecoder)
            val container = decoder.decodeJsonElement()
            return when (val discriminator = container.jsonObject["type"]?.jsonPrimitive?.content) {
                "UnitVariant" -> UnitVariant
                "TupleVariant" -> {
                    val content = decoder.json.decodeFromJsonElement<String>(container)
                    TupleVariant(content)
                }
                "StructVariant" -> {
                    decoder.json.decodeFromJsonElement<StructVariant>(container)
                }
                else ->
                        throw Exception(
                                "Unknown enum variant $discriminator for InternallyTaggedEnum"
                        )
            }
        }
    }
}

@Parcelize
@Serializable
@JsonClassDiscriminator("type")
sealed interface AdjacentlyTaggedEnum : Parcelable {
    @Serializable @SerialName("UnitVariant") data object UnitVariant : AdjacentlyTaggedEnum

    @Serializable
    @SerialName("TupleVariant")
    data class TupleVariant(val content: String) : AdjacentlyTaggedEnum

    @Serializable(with = StructVariant.Serializer::class)
    data class StructVariant(val field: String) : AdjacentlyTaggedEnum {
        object Serializer : KSerializer<StructVariant> {
            @Serializable private data class Content(val field: String)

            override val descriptor =
                    buildClassSerialDescriptor("StructVariant") { element<Content>("content") }

            override fun serialize(encoder: Encoder, value: StructVariant) {
                encoder.encodeStructure(descriptor) {
                    encodeSerializableElement(
                            descriptor,
                            0,
                            Content.serializer(),
                            Content(value.field)
                    )
                }
            }

            override fun deserialize(decoder: Decoder): StructVariant {
                val content =
                        decoder.decodeStructure(descriptor) {
                            assert(
                                    decodeElementIndex(descriptor) == 0
                            ) // The structure only contains a single index
                            decodeSerializableElement(descriptor, 0, Content.serializer())
                        }

                return TestWithAnonymousStruct(content.field)
            }
        }
    }
}