-
Notifications
You must be signed in to change notification settings - Fork 612
/
Enums.kt
124 lines (106 loc) · 4.16 KB
/
Enums.kt
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
/*
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.serialization.internal
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlin.jvm.Volatile
/*
* Descriptor used for explicitly serializable enums by the plugin.
* Designed to be consistent with `EnumSerializer.descriptor` and weird plugin usage.
*/
@Suppress("unused") // Used by the plugin
@PublishedApi
@OptIn(ExperimentalSerializationApi::class)
internal class EnumDescriptor(
name: String,
elementsCount: Int
) : PluginGeneratedSerialDescriptor(name, elementsCount = elementsCount) {
override val kind: SerialKind = SerialKind.ENUM
private val elementDescriptors by lazy {
Array(elementsCount) { buildSerialDescriptor(name + "." + getElementName(it), StructureKind.OBJECT) }
}
override fun getElementDescriptor(index: Int): SerialDescriptor = elementDescriptors.getChecked(index)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
if (other !is SerialDescriptor) return false
if (other.kind !== SerialKind.ENUM) return false
if (serialName != other.serialName) return false
if (cachedSerialNames() != other.cachedSerialNames()) return false
return true
}
override fun toString(): String {
return elementNames.joinToString(", ", "$serialName(", ")")
}
override fun hashCode(): Int {
var result = serialName.hashCode()
val elementsHashCode = elementNames.elementsHashCodeBy { it }
result = 31 * result + elementsHashCode
return result
}
}
@OptIn(ExperimentalSerializationApi::class)
@InternalSerializationApi
internal fun <T : Enum<T>> createSimpleEnumSerializer(serialName: String, values: Array<T>): KSerializer<T> {
return EnumSerializer(serialName, values)
}
@OptIn(ExperimentalSerializationApi::class)
@InternalSerializationApi
internal fun <T : Enum<T>> createMarkedEnumSerializer(
serialName: String,
values: Array<T>,
names: Array<String?>,
annotations: Array<Array<Annotation>?>
): KSerializer<T> {
val descriptor = EnumDescriptor(serialName, values.size)
values.forEachIndexed { i, v ->
val elementName = names.getOrNull(i) ?: v.name
descriptor.addElement(elementName)
annotations.getOrNull(i)?.forEach {
descriptor.pushAnnotation(it)
}
}
return EnumSerializer(serialName, values, descriptor)
}
@PublishedApi
@OptIn(ExperimentalSerializationApi::class)
internal class EnumSerializer<T : Enum<T>>(
serialName: String,
private val values: Array<T>
) : KSerializer<T> {
private var overriddenDescriptor: SerialDescriptor? = null
internal constructor(serialName: String, values: Array<T>, descriptor: SerialDescriptor) : this(serialName, values) {
overriddenDescriptor = descriptor
}
override val descriptor: SerialDescriptor by lazy {
overriddenDescriptor ?: createUnmarkedDescriptor(serialName)
}
private fun createUnmarkedDescriptor(serialName: String): SerialDescriptor {
val d = EnumDescriptor(serialName, values.size)
values.forEach { d.addElement(it.name) }
return d
}
override fun serialize(encoder: Encoder, value: T) {
val index = values.indexOf(value)
if (index == -1) {
throw SerializationException(
"$value is not a valid enum ${descriptor.serialName}, " +
"must be one of ${values.contentToString()}"
)
}
encoder.encodeEnum(descriptor, index)
}
override fun deserialize(decoder: Decoder): T {
val index = decoder.decodeEnum(descriptor)
if (index !in values.indices) {
throw SerializationException(
"$index is not among valid ${descriptor.serialName} enum values, " +
"values size is ${values.size}"
)
}
return values[index]
}
override fun toString(): String = "kotlinx.serialization.internal.EnumSerializer<${descriptor.serialName}>"
}