summaryrefslogtreecommitdiff
path: root/runtime/commonMain/src/kotlinx/serialization/modules/PolymorphicModuleBuilder.kt
blob: e178b62afca573a3279535d03192a39eca5bb03c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
 * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

@file:Suppress("RedundantVisibilityModifier")

package kotlinx.serialization.modules

import kotlinx.serialization.*
import kotlin.reflect.*

/**
 * A builder which registers all its content for polymorphic serialization in the scope of [baseClass].
 * If [baseSerializer] is present, registers it as a serializer for [baseClass] (which will be used if base class is serializable).
 * Subclasses with its serializers can be added via [addSubclass] or [with].
 *
 * To obtain an instance of this builder, use [SerializersModuleBuilder.polymorphic] DSL function.
 */
@Suppress("UNCHECKED_CAST")
public class PolymorphicModuleBuilder<Base : Any> internal constructor(
    private val baseClass: KClass<Base>,
    private val baseSerializer: KSerializer<Base>? = null
) {
    private val subclasses: MutableList<Pair<KClass<out Base>, KSerializer<out Base>>> = mutableListOf()

    internal fun buildTo(module: SerialModuleImpl) {
        if (baseSerializer != null) module.registerPolymorphicSerializer(baseClass, baseClass, baseSerializer)
        subclasses.forEach { (kclass, serializer) ->
            module.registerPolymorphicSerializer(
                baseClass,
                kclass as KClass<Base>,
                serializer as KSerializer<Base>
            )
        }
    }

    /**
     * Adds a [subclass] [serializer] to the resulting module under the initial [baseClass].
     */
    public fun <T : Base> addSubclass(subclass: KClass<T>, serializer: KSerializer<T>) {
        subclasses.add(subclass to serializer)
    }

    /**
     * @see addSubclass
     */
    public inline fun <reified T : Base> addSubclass(serializer: KSerializer<T>): Unit =
        addSubclass(T::class, serializer)

    /**
     * @see addSubclass
     */
    @ImplicitReflectionSerializer
    public inline fun <reified T : Base> addSubclass(): Unit = addSubclass(T::class, T::class.serializer())

    /**
     * @see addSubclass
     */
    public infix fun <T : Base> KClass<T>.with(serializer: KSerializer<T>): Unit = addSubclass(this, serializer)


    /**
     * Adds all subtypes of this builder to a new builder with a scope of [newBaseClass].
     *
     * If base type of this module had a serializer, adds it, too.
     *
     * @param newBaseClass A new base polymorphic type. Should be supertype of current [baseClass].
     * @param newBaseClassSerializer Serializer for the new base type, if needed.
     * @return A new builder with subclasses from this and [newBaseClass] as baseClass.
     */
    internal fun <NewBase : Any> changeBase(
        newBaseClass: KClass<NewBase>,
        newBaseClassSerializer: KSerializer<NewBase>? = null
    ): PolymorphicModuleBuilder<NewBase> {
        val newModule = PolymorphicModuleBuilder(newBaseClass, newBaseClassSerializer)
        baseSerializer?.let { newModule.addSubclass(baseClass as KClass<NewBase>, baseSerializer as KSerializer<NewBase>) }
        subclasses.forEach { (k, v) ->
            newModule.addSubclass(k as KClass<NewBase>, v as KSerializer<NewBase>)
        }
        return newModule
    }
}