1 /*
2  * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 @file:OptIn(ExperimentalSerializationApi::class)
5 
6 package kotlinx.serialization.json.internal
7 
8 import kotlinx.serialization.*
9 import kotlinx.serialization.descriptors.*
10 import kotlinx.serialization.json.*
11 import kotlinx.serialization.modules.*
12 import kotlin.jvm.*
13 
14 internal enum class WriteMode(@JvmField val begin: Char, @JvmField val end: Char) {
15     OBJ(BEGIN_OBJ, END_OBJ),
16     LIST(BEGIN_LIST, END_LIST),
17     MAP(BEGIN_OBJ, END_OBJ),
18     POLY_OBJ(BEGIN_LIST, END_LIST);
19 }
20 
21 @OptIn(ExperimentalSerializationApi::class)
switchModenull22 internal fun Json.switchMode(desc: SerialDescriptor): WriteMode =
23     when (desc.kind) {
24         is PolymorphicKind -> WriteMode.POLY_OBJ
25         StructureKind.LIST -> WriteMode.LIST
26         StructureKind.MAP -> selectMapMode(desc, { WriteMode.MAP }, { WriteMode.LIST })
27         else -> WriteMode.OBJ
28     }
29 
30 @OptIn(ExperimentalSerializationApi::class)
selectMapModenull31 internal inline fun <T, R1 : T, R2 : T> Json.selectMapMode(
32     mapDescriptor: SerialDescriptor,
33     ifMap: () -> R1,
34     ifList: () -> R2
35 ): T {
36     val keyDescriptor = mapDescriptor.getElementDescriptor(0).carrierDescriptor(serializersModule)
37     val keyKind = keyDescriptor.kind
38 
39     return if (keyKind is PrimitiveKind || keyKind == SerialKind.ENUM) {
40         ifMap()
41     } else if (configuration.allowStructuredMapKeys) {
42         ifList()
43     } else {
44         throw InvalidKeyKindException(keyDescriptor)
45     }
46 }
47 
carrierDescriptornull48 internal fun SerialDescriptor.carrierDescriptor(module: SerializersModule): SerialDescriptor = when {
49     kind == SerialKind.CONTEXTUAL -> module.getContextualDescriptor(this)?.carrierDescriptor(module) ?: this
50     isInline -> getElementDescriptor(0).carrierDescriptor(module)
51     else     -> this
52 }
53