-
Notifications
You must be signed in to change notification settings - Fork 612
/
CollectionSerializers.kt
281 lines (239 loc) · 12.9 KB
/
CollectionSerializers.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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/*
* Copyright 2017-2020 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.reflect.*
@InternalSerializationApi
public sealed class AbstractCollectionSerializer<Element, Collection, Builder> : KSerializer<Collection> {
protected abstract fun Collection.collectionSize(): Int
protected abstract fun Collection.collectionIterator(): Iterator<Element>
protected abstract fun builder(): Builder
protected abstract fun Builder.builderSize(): Int
protected abstract fun Builder.toResult(): Collection
protected abstract fun Collection.toBuilder(): Builder
protected abstract fun Builder.checkCapacity(size: Int)
abstract override fun serialize(encoder: Encoder, value: Collection)
@InternalSerializationApi
public fun merge(decoder: Decoder, previous: Collection?): Collection {
val builder = previous?.toBuilder() ?: builder()
val startIndex = builder.builderSize()
val compositeDecoder = decoder.beginStructure(descriptor)
if (compositeDecoder.decodeSequentially()) {
readAll(compositeDecoder, builder, startIndex, readSize(compositeDecoder, builder))
} else {
while (true) {
val index = compositeDecoder.decodeElementIndex(descriptor)
if (index == CompositeDecoder.DECODE_DONE) break
readElement(compositeDecoder, startIndex + index, builder)
}
}
compositeDecoder.endStructure(descriptor)
return builder.toResult()
}
override fun deserialize(decoder: Decoder): Collection = merge(decoder, null)
private fun readSize(decoder: CompositeDecoder, builder: Builder): Int {
val size = decoder.decodeCollectionSize(descriptor)
builder.checkCapacity(size)
return size
}
protected abstract fun readElement(decoder: CompositeDecoder, index: Int, builder: Builder, checkIndex: Boolean = true)
protected abstract fun readAll(decoder: CompositeDecoder, builder: Builder, startIndex: Int, size: Int)
}
@PublishedApi
internal sealed class ListLikeSerializer<Element, Collection, Builder>(
private val elementSerializer: KSerializer<Element>
) : AbstractCollectionSerializer<Element, Collection, Builder>() {
protected abstract fun Builder.insert(index: Int, element: Element)
abstract override val descriptor: SerialDescriptor
override fun serialize(encoder: Encoder, value: Collection) {
val size = value.collectionSize()
encoder.encodeCollection(descriptor, size) {
val iterator = value.collectionIterator()
for (index in 0 until size)
encodeSerializableElement(descriptor, index, elementSerializer, iterator.next())
}
}
protected final override fun readAll(decoder: CompositeDecoder, builder: Builder, startIndex: Int, size: Int) {
require(size >= 0) { "Size must be known in advance when using READ_ALL" }
for (index in 0 until size)
readElement(decoder, startIndex + index, builder, checkIndex = false)
}
protected override fun readElement(decoder: CompositeDecoder, index: Int, builder: Builder, checkIndex: Boolean) {
builder.insert(index, decoder.decodeSerializableElement(descriptor, index, elementSerializer))
}
}
@InternalSerializationApi // TODO tech debt: it's used in ProtoBuf
public sealed class MapLikeSerializer<Key, Value, Collection, Builder : MutableMap<Key, Value>>(
public val keySerializer: KSerializer<Key>,
public val valueSerializer: KSerializer<Value>
) : AbstractCollectionSerializer<Map.Entry<Key, Value>, Collection, Builder>() {
protected abstract fun Builder.insertKeyValuePair(index: Int, key: Key, value: Value)
abstract override val descriptor: SerialDescriptor
protected final override fun readAll(decoder: CompositeDecoder, builder: Builder, startIndex: Int, size: Int) {
require(size >= 0) { "Size must be known in advance when using READ_ALL" }
for (index in 0 until size * 2 step 2)
readElement(decoder, startIndex + index, builder, checkIndex = false)
}
final override fun readElement(decoder: CompositeDecoder, index: Int, builder: Builder, checkIndex: Boolean) {
val key: Key = decoder.decodeSerializableElement(descriptor, index, keySerializer)
val vIndex = if (checkIndex) {
decoder.decodeElementIndex(descriptor).also {
require(it == index + 1) { "Value must follow key in a map, index for key: $index, returned index for value: $it" }
}
} else {
index + 1
}
val value: Value = if (builder.containsKey(key) && valueSerializer.descriptor.kind !is PrimitiveKind) {
decoder.decodeSerializableElement(descriptor, vIndex, valueSerializer, builder.getValue(key))
} else {
decoder.decodeSerializableElement(descriptor, vIndex, valueSerializer)
}
builder[key] = value
}
override fun serialize(encoder: Encoder, value: Collection) {
val size = value.collectionSize()
encoder.encodeCollection(descriptor, size) {
val iterator = value.collectionIterator()
var index = 0
iterator.forEach { (k, v) ->
encodeSerializableElement(descriptor, index++, keySerializer, k)
encodeSerializableElement(descriptor, index++, valueSerializer, v)
}
}
}
}
@PublishedApi
internal abstract class PrimitiveArrayBuilder<Array> internal constructor() {
internal abstract val position: Int
internal abstract fun ensureCapacity(requiredCapacity: Int = position + 1)
internal abstract fun build(): Array
}
/**
* Base serializer for all serializers for primitive arrays.
*
* It exists only to avoid code duplication and should not be used or implemented directly.
* Use concrete serializers ([ByteArraySerializer], etc) instead.
*/
@PublishedApi
internal abstract class PrimitiveArraySerializer<Element, Array, Builder
: PrimitiveArrayBuilder<Array>> internal constructor(
primitiveSerializer: KSerializer<Element>
) : ListLikeSerializer<Element, Array, Builder>(primitiveSerializer) {
final override val descriptor: SerialDescriptor = PrimitiveArrayDescriptor(primitiveSerializer.descriptor)
final override fun Builder.builderSize(): Int = position
final override fun Builder.toResult(): Array = build()
final override fun Builder.checkCapacity(size: Int): Unit = ensureCapacity(size)
final override fun Array.collectionIterator(): Iterator<Element> =
error("This method lead to boxing and must not be used, use writeContents instead")
final override fun Builder.insert(index: Int, element: Element): Unit =
error("This method lead to boxing and must not be used, use Builder.append instead")
final override fun builder(): Builder = empty().toBuilder()
protected abstract fun empty(): Array
protected abstract override fun readElement(
decoder: CompositeDecoder,
index: Int,
builder: Builder,
checkIndex: Boolean
)
protected abstract fun writeContent(encoder: CompositeEncoder, content: Array, size: Int)
final override fun serialize(encoder: Encoder, value: Array) {
val size = value.collectionSize()
encoder.encodeCollection(descriptor, size) {
writeContent(this, value, size)
}
}
final override fun deserialize(decoder: Decoder): Array = merge(decoder, null)
}
// todo: can be more efficient when array size is know in advance, this one always uses temporary ArrayList as builder
@PublishedApi
internal class ReferenceArraySerializer<ElementKlass : Any, Element : ElementKlass?>(
private val kClass: KClass<ElementKlass>,
eSerializer: KSerializer<Element>
) : ListLikeSerializer<Element, Array<Element>, ArrayList<Element>>(eSerializer) {
override val descriptor: SerialDescriptor = ArrayClassDesc(eSerializer.descriptor)
override fun Array<Element>.collectionSize(): Int = size
override fun Array<Element>.collectionIterator(): Iterator<Element> = iterator()
override fun builder(): ArrayList<Element> = arrayListOf()
override fun ArrayList<Element>.builderSize(): Int = size
@Suppress("UNCHECKED_CAST")
override fun ArrayList<Element>.toResult(): Array<Element> = toNativeArrayImpl<ElementKlass, Element>(kClass)
override fun Array<Element>.toBuilder(): ArrayList<Element> = ArrayList(this.asList())
override fun ArrayList<Element>.checkCapacity(size: Int): Unit = ensureCapacity(size)
override fun ArrayList<Element>.insert(index: Int, element: Element) {
add(index, element)
}
}
@InternalSerializationApi
@PublishedApi
internal class ArrayListSerializer<E>(element: KSerializer<E>) : ListLikeSerializer<E, List<E>, ArrayList<E>>(element) {
override val descriptor: SerialDescriptor = ArrayListClassDesc(element.descriptor)
override fun List<E>.collectionSize(): Int = size
override fun List<E>.collectionIterator(): Iterator<E> = iterator()
override fun builder(): ArrayList<E> = arrayListOf()
override fun ArrayList<E>.builderSize(): Int = size
override fun ArrayList<E>.toResult(): List<E> = this
override fun List<E>.toBuilder(): ArrayList<E> = this as? ArrayList<E> ?: ArrayList(this)
override fun ArrayList<E>.checkCapacity(size: Int): Unit = ensureCapacity(size)
override fun ArrayList<E>.insert(index: Int, element: E) { add(index, element) }
}
@PublishedApi
internal class LinkedHashSetSerializer<E>(
eSerializer: KSerializer<E>
) : ListLikeSerializer<E, Set<E>, LinkedHashSet<E>>(eSerializer) {
override val descriptor: SerialDescriptor = LinkedHashSetClassDesc(eSerializer.descriptor)
override fun Set<E>.collectionSize(): Int = size
override fun Set<E>.collectionIterator(): Iterator<E> = iterator()
override fun builder(): LinkedHashSet<E> = linkedSetOf()
override fun LinkedHashSet<E>.builderSize(): Int = size
override fun LinkedHashSet<E>.toResult(): Set<E> = this
override fun Set<E>.toBuilder(): LinkedHashSet<E> = this as? LinkedHashSet<E> ?: LinkedHashSet(this)
override fun LinkedHashSet<E>.checkCapacity(size: Int) {}
override fun LinkedHashSet<E>.insert(index: Int, element: E) { add(element) }
}
@PublishedApi
internal class HashSetSerializer<E>(
eSerializer: KSerializer<E>
) : ListLikeSerializer<E, Set<E>, HashSet<E>>(eSerializer) {
override val descriptor: SerialDescriptor = HashSetClassDesc(eSerializer.descriptor)
override fun Set<E>.collectionSize(): Int = size
override fun Set<E>.collectionIterator(): Iterator<E> = iterator()
override fun builder(): HashSet<E> = HashSet()
override fun HashSet<E>.builderSize(): Int = size
override fun HashSet<E>.toResult(): Set<E> = this
override fun Set<E>.toBuilder(): HashSet<E> = this as? HashSet<E> ?: HashSet(this)
override fun HashSet<E>.checkCapacity(size: Int) {}
override fun HashSet<E>.insert(index: Int, element: E) { add(element) }
}
@PublishedApi
internal class LinkedHashMapSerializer<K, V>(
kSerializer: KSerializer<K>, vSerializer: KSerializer<V>
) : MapLikeSerializer<K, V, Map<K, V>, LinkedHashMap<K, V>>(kSerializer, vSerializer) {
override val descriptor: SerialDescriptor = LinkedHashMapClassDesc(kSerializer.descriptor, vSerializer.descriptor)
override fun Map<K, V>.collectionSize(): Int = size
override fun Map<K, V>.collectionIterator(): Iterator<Map.Entry<K, V>> = iterator()
override fun builder(): LinkedHashMap<K, V> = LinkedHashMap()
override fun LinkedHashMap<K, V>.builderSize(): Int = size * 2
override fun LinkedHashMap<K, V>.toResult(): Map<K, V> = this
override fun Map<K, V>.toBuilder(): LinkedHashMap<K, V> = this as? LinkedHashMap<K, V> ?: LinkedHashMap(this)
override fun LinkedHashMap<K, V>.checkCapacity(size: Int) {}
override fun LinkedHashMap<K, V>.insertKeyValuePair(index: Int, key: K, value: V): Unit = set(key, value)
}
@PublishedApi
internal class HashMapSerializer<K, V>(
kSerializer: KSerializer<K>, vSerializer: KSerializer<V>
) : MapLikeSerializer<K, V, Map<K, V>, HashMap<K, V>>(kSerializer, vSerializer) {
override val descriptor: SerialDescriptor = HashMapClassDesc(kSerializer.descriptor, vSerializer.descriptor)
override fun Map<K, V>.collectionSize(): Int = size
override fun Map<K, V>.collectionIterator(): Iterator<Map.Entry<K, V>> = iterator()
override fun builder(): HashMap<K, V> = HashMap()
override fun HashMap<K, V>.builderSize(): Int = size * 2
override fun HashMap<K, V>.toResult(): Map<K, V> = this
override fun Map<K, V>.toBuilder(): HashMap<K, V> = this as? HashMap<K, V> ?: HashMap(this)
override fun HashMap<K, V>.checkCapacity(size: Int) {}
override fun HashMap<K, V>.insertKeyValuePair(index: Int, key: K, value: V): Unit = set(key, value)
}