summaryrefslogtreecommitdiff
path: root/core/commonMain/src/kotlinx/serialization/internal/Tuples.kt
blob: 1bd21cbe3496a9b0879371b239e4b2814b351ddc (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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */
@file:Suppress("DEPRECATION_ERROR")
@file:OptIn(ExperimentalSerializationApi::class)

package kotlinx.serialization.internal

import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.native.concurrent.*

private val NULL = Any()
private const val deprecationMessage =
    "This class is used only by the plugin in generated code and should not be used directly. Use corresponding factory functions instead"

@PublishedApi
internal sealed class KeyValueSerializer<K, V, R>(
    protected val keySerializer: KSerializer<K>,
    protected val valueSerializer: KSerializer<V>
) : KSerializer<R> {

    protected abstract val R.key: K
    protected abstract val R.value: V
    protected abstract fun toResult(key: K, value: V): R

    override fun serialize(encoder: Encoder, value: R) {
        val structuredEncoder = encoder.beginStructure(descriptor)
        structuredEncoder.encodeSerializableElement(descriptor, 0, keySerializer, value.key)
        structuredEncoder.encodeSerializableElement(descriptor, 1, valueSerializer, value.value)
        structuredEncoder.endStructure(descriptor)
    }

    override fun deserialize(decoder: Decoder): R = decoder.decodeStructure(descriptor) {
        if (decodeSequentially()) {
            val key = decodeSerializableElement(descriptor, 0, keySerializer)
            val value = decodeSerializableElement(descriptor, 1, valueSerializer)
            return@decodeStructure toResult(key, value)
        }

        var key: Any? = NULL
        var value: Any? = NULL
        mainLoop@ while (true) {
            when (val idx = decodeElementIndex(descriptor)) {
                CompositeDecoder.DECODE_DONE -> {
                    break@mainLoop
                }
                0 -> {
                    key = decodeSerializableElement(descriptor, 0, keySerializer)
                }
                1 -> {
                    value = decodeSerializableElement(descriptor, 1, valueSerializer)
                }
                else -> throw SerializationException("Invalid index: $idx")
            }
        }
        if (key === NULL) throw SerializationException("Element 'key' is missing")
        if (value === NULL) throw SerializationException("Element 'value' is missing")
        @Suppress("UNCHECKED_CAST")
        return@decodeStructure toResult(key as K, value as V)
    }
}

@PublishedApi
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
internal class MapEntrySerializer<K, V>(
    keySerializer: KSerializer<K>,
    valueSerializer: KSerializer<V>
) : KeyValueSerializer<K, V, Map.Entry<K, V>>(keySerializer, valueSerializer) {
    private data class MapEntry<K, V>(override val key: K, override val value: V) : Map.Entry<K, V>

    /*
     * Kind 'MAP' because it is represented in a map-like manner with "key: value" serialized directly
     */
    override val descriptor: SerialDescriptor = buildSerialDescriptor("kotlin.collections.Map.Entry", StructureKind.MAP) {
        element("key", keySerializer.descriptor)
        element("value", valueSerializer.descriptor)
    }

    override val Map.Entry<K, V>.key: K get() = this.key
    override val Map.Entry<K, V>.value: V get() = this.value
    override fun toResult(key: K, value: V): Map.Entry<K, V> = MapEntry(key, value)
}

@PublishedApi
internal class PairSerializer<K, V>(
    keySerializer: KSerializer<K>,
    valueSerializer: KSerializer<V>
) : KeyValueSerializer<K, V, Pair<K, V>>(keySerializer, valueSerializer) {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("kotlin.Pair") {
        element("first", keySerializer.descriptor)
        element("second", valueSerializer.descriptor)
    }
    override val Pair<K, V>.key: K get() = this.first
    override val Pair<K, V>.value: V get() = this.second

    override fun toResult(key: K, value: V): Pair<K, V> = key to value
}


@PublishedApi
internal class TripleSerializer<A, B, C>(
    private val aSerializer: KSerializer<A>,
    private val bSerializer: KSerializer<B>,
    private val cSerializer: KSerializer<C>
) : KSerializer<Triple<A, B, C>> {

    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("kotlin.Triple") {
        element("first", aSerializer.descriptor)
        element("second", bSerializer.descriptor)
        element("third", cSerializer.descriptor)
    }

    override fun serialize(encoder: Encoder, value: Triple<A, B, C>) {
        val structuredEncoder = encoder.beginStructure(descriptor)
        structuredEncoder.encodeSerializableElement(descriptor, 0, aSerializer, value.first)
        structuredEncoder.encodeSerializableElement(descriptor, 1, bSerializer, value.second)
        structuredEncoder.encodeSerializableElement(descriptor, 2, cSerializer, value.third)
        structuredEncoder.endStructure(descriptor)
    }

    override fun deserialize(decoder: Decoder): Triple<A, B, C> {
        val composite = decoder.beginStructure(descriptor)
        if (composite.decodeSequentially()) {
            return decodeSequentially(composite)
        }
        return decodeStructure(composite)
    }

    private fun decodeSequentially(composite: CompositeDecoder): Triple<A, B, C> {
        val a = composite.decodeSerializableElement(descriptor, 0, aSerializer)
        val b = composite.decodeSerializableElement(descriptor, 1, bSerializer)
        val c = composite.decodeSerializableElement(descriptor, 2, cSerializer)
        composite.endStructure(descriptor)
        return Triple(a, b, c)
    }

    private fun decodeStructure(composite: CompositeDecoder): Triple<A, B, C> {
        var a: Any? = NULL
        var b: Any? = NULL
        var c: Any? = NULL
        mainLoop@ while (true) {
            when (val index = composite.decodeElementIndex(descriptor)) {
                CompositeDecoder.DECODE_DONE -> {
                    break@mainLoop
                }
                0 -> {
                    a = composite.decodeSerializableElement(descriptor, 0, aSerializer)
                }
                1 -> {
                    b = composite.decodeSerializableElement(descriptor, 1, bSerializer)
                }
                2 -> {
                    c = composite.decodeSerializableElement(descriptor, 2, cSerializer)
                }
                else -> throw SerializationException("Unexpected index $index")
            }
        }
        composite.endStructure(descriptor)
        if (a === NULL) throw SerializationException("Element 'first' is missing")
        if (b === NULL) throw SerializationException("Element 'second' is missing")
        if (c === NULL) throw SerializationException("Element 'third' is missing")
        @Suppress("UNCHECKED_CAST")
        return Triple(a as A, b as B, c as C)
    }
}