1 /*
2  * Copyright 2017-2020 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.internal
7 
8 import kotlinx.serialization.*
9 import kotlinx.serialization.descriptors.*
10 
11 @ExperimentalSerializationApi
12 internal sealed class ListLikeDescriptor(val elementDescriptor: SerialDescriptor) : SerialDescriptor {
13     override val kind: SerialKind get() = StructureKind.LIST
14     override val elementsCount: Int = 1
15 
getElementNamenull16     override fun getElementName(index: Int): String = index.toString()
17     override fun getElementIndex(name: String): Int =
18         name.toIntOrNull() ?: throw IllegalArgumentException("$name is not a valid list index")
19 
20     override fun isElementOptional(index: Int): Boolean {
21         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
22         return false
23     }
24 
getElementAnnotationsnull25     override fun getElementAnnotations(index: Int): List<Annotation> {
26         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
27         return emptyList()
28     }
29 
getElementDescriptornull30     override fun getElementDescriptor(index: Int): SerialDescriptor {
31         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
32         return elementDescriptor
33     }
34 
equalsnull35     override fun equals(other: Any?): Boolean {
36         if (this === other) return true
37         if (other !is ListLikeDescriptor) return false
38         if (elementDescriptor == other.elementDescriptor && serialName == other.serialName) return true
39         return false
40     }
41 
hashCodenull42     override fun hashCode(): Int {
43         return elementDescriptor.hashCode() * 31 + serialName.hashCode()
44     }
45 
toStringnull46     override fun toString(): String = "$serialName($elementDescriptor)"
47 }
48 
49 internal sealed class MapLikeDescriptor(
50     override val serialName: String,
51     val keyDescriptor: SerialDescriptor,
52     val valueDescriptor: SerialDescriptor
53 ) : SerialDescriptor {
54     override val kind: SerialKind get() = StructureKind.MAP
55     override val elementsCount: Int = 2
56     override fun getElementName(index: Int): String = index.toString()
57     override fun getElementIndex(name: String): Int =
58         name.toIntOrNull() ?: throw IllegalArgumentException("$name is not a valid map index")
59 
60     override fun isElementOptional(index: Int): Boolean {
61         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
62         return false
63     }
64 
65     override fun getElementAnnotations(index: Int): List<Annotation> {
66         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
67         return emptyList()
68     }
69 
70     override fun getElementDescriptor(index: Int): SerialDescriptor {
71         require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
72         return when (index % 2) {
73             0 -> keyDescriptor
74             1 -> valueDescriptor
75             else -> error("Unreached")
76         }
77     }
78 
79     override fun equals(other: Any?): Boolean {
80         if (this === other) return true
81         if (other !is MapLikeDescriptor) return false
82         if (serialName != other.serialName) return false
83         if (keyDescriptor != other.keyDescriptor) return false
84         if (valueDescriptor != other.valueDescriptor) return false
85         return true
86     }
87 
88     override fun hashCode(): Int {
89         var result = serialName.hashCode()
90         result = 31 * result + keyDescriptor.hashCode()
91         result = 31 * result + valueDescriptor.hashCode()
92         return result
93     }
94 
95     override fun toString(): String = "$serialName($keyDescriptor, $valueDescriptor)"
96 }
97 
98 internal const val ARRAY_NAME = "kotlin.Array"
99 internal const val ARRAY_LIST_NAME = "kotlin.collections.ArrayList"
100 internal const val LINKED_HASH_SET_NAME = "kotlin.collections.LinkedHashSet"
101 internal const val HASH_SET_NAME = "kotlin.collections.HashSet"
102 internal const val LINKED_HASH_MAP_NAME = "kotlin.collections.LinkedHashMap"
103 internal const val HASH_MAP_NAME = "kotlin.collections.HashMap"
104 
105 /**
106  * Descriptor for primitive arrays, such as [IntArray], [DoubleArray], etc...
107  *
108  * Can be obtained from corresponding serializers (e.g. [ByteArraySerializer.descriptor])
109  */
110 @OptIn(ExperimentalSerializationApi::class)
111 internal class PrimitiveArrayDescriptor internal constructor(
112     primitive: SerialDescriptor
113 ) : ListLikeDescriptor(primitive) {
114     override val serialName: String = "${primitive.serialName}Array"
115 }
116 
117 internal class ArrayClassDesc(elementDesc: SerialDescriptor) : ListLikeDescriptor(elementDesc) {
118     override val serialName: String get() = ARRAY_NAME
119 }
120 
121 internal class ArrayListClassDesc(elementDesc: SerialDescriptor) : ListLikeDescriptor(elementDesc) {
122     override val serialName: String get() = ARRAY_LIST_NAME
123 }
124 
125 internal class LinkedHashSetClassDesc(elementDesc: SerialDescriptor) : ListLikeDescriptor(elementDesc) {
126     override val serialName: String get() = LINKED_HASH_SET_NAME
127 }
128 
129 internal class HashSetClassDesc(elementDesc: SerialDescriptor) : ListLikeDescriptor(elementDesc) {
130     override val serialName: String get() = HASH_SET_NAME
131 }
132 
133 internal class LinkedHashMapClassDesc(keyDesc: SerialDescriptor, valueDesc: SerialDescriptor) :
134     MapLikeDescriptor(LINKED_HASH_MAP_NAME, keyDesc, valueDesc)
135 
136 internal class HashMapClassDesc(keyDesc: SerialDescriptor, valueDesc: SerialDescriptor) :
137     MapLikeDescriptor(HASH_MAP_NAME, keyDesc, valueDesc)
138