![JAR search and dependency download from the Maven repository](/logo.png)
commonMain.kotlinx.serialization.internal.CollectionSerializers.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-serialization-core-jvm Show documentation
Show all versions of kotlinx-serialization-core-jvm Show documentation
Kotlin multiplatform serialization runtime library
The newest version!
/*
* 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 : KSerializer {
protected abstract fun Collection.collectionSize(): Int
protected abstract fun Collection.collectionIterator(): Iterator
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 CollectionLikeSerializer(
private val elementSerializer: KSerializer
) : AbstractCollectionSerializer() {
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())
}
}
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)
}
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>(
public val keySerializer: KSerializer,
public val valueSerializer: KSerializer
) : AbstractCollectionSerializer, 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 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> internal constructor(
primitiveSerializer: KSerializer
) : CollectionLikeSerializer(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 =
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
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(
private val kClass: KClass,
eSerializer: KSerializer
) : CollectionLikeSerializer, ArrayList>(eSerializer) {
override val descriptor: SerialDescriptor = ArrayClassDesc(eSerializer.descriptor)
override fun Array.collectionSize(): Int = size
override fun Array.collectionIterator(): Iterator = iterator()
override fun builder(): ArrayList = arrayListOf()
override fun ArrayList.builderSize(): Int = size
@Suppress("UNCHECKED_CAST")
override fun ArrayList.toResult(): Array = toNativeArrayImpl(kClass)
override fun Array.toBuilder(): ArrayList = ArrayList(this.asList())
override fun ArrayList.checkCapacity(size: Int): Unit = ensureCapacity(size)
override fun ArrayList.insert(index: Int, element: Element) {
add(index, element)
}
}
@PublishedApi
internal abstract class CollectionSerializer, B>(element: KSerializer) : CollectionLikeSerializer(element) {
override fun C.collectionSize(): Int = size
override fun C.collectionIterator(): Iterator = iterator()
}
@InternalSerializationApi
@PublishedApi
internal class ArrayListSerializer(element: KSerializer) : CollectionSerializer, ArrayList>(element) {
override val descriptor: SerialDescriptor = ArrayListClassDesc(element.descriptor)
override fun builder(): ArrayList = arrayListOf()
override fun ArrayList.builderSize(): Int = size
override fun ArrayList.toResult(): List = this
override fun List.toBuilder(): ArrayList = this as? ArrayList ?: ArrayList(this)
override fun ArrayList.checkCapacity(size: Int): Unit = ensureCapacity(size)
override fun ArrayList.insert(index: Int, element: E) { add(index, element) }
}
@PublishedApi
internal class LinkedHashSetSerializer(
eSerializer: KSerializer
) : CollectionSerializer, LinkedHashSet>(eSerializer) {
override val descriptor: SerialDescriptor = LinkedHashSetClassDesc(eSerializer.descriptor)
override fun builder(): LinkedHashSet = linkedSetOf()
override fun LinkedHashSet.builderSize(): Int = size
override fun LinkedHashSet.toResult(): Set = this
override fun Set.toBuilder(): LinkedHashSet = this as? LinkedHashSet ?: LinkedHashSet(this)
override fun LinkedHashSet.checkCapacity(size: Int) {}
override fun LinkedHashSet.insert(index: Int, element: E) { add(element) }
}
@PublishedApi
internal class HashSetSerializer(
eSerializer: KSerializer
) : CollectionSerializer, HashSet>(eSerializer) {
override val descriptor: SerialDescriptor = HashSetClassDesc(eSerializer.descriptor)
override fun builder(): HashSet = HashSet()
override fun HashSet.builderSize(): Int = size
override fun HashSet.toResult(): Set = this
override fun Set.toBuilder(): HashSet = this as? HashSet ?: HashSet(this)
override fun HashSet.checkCapacity(size: Int) {}
override fun HashSet.insert(index: Int, element: E) { add(element) }
}
@PublishedApi
internal class LinkedHashMapSerializer(
kSerializer: KSerializer, vSerializer: KSerializer
) : MapLikeSerializer, LinkedHashMap>(kSerializer, vSerializer) {
override val descriptor: SerialDescriptor = LinkedHashMapClassDesc(kSerializer.descriptor, vSerializer.descriptor)
override fun Map.collectionSize(): Int = size
override fun Map.collectionIterator(): Iterator> = iterator()
override fun builder(): LinkedHashMap = LinkedHashMap()
override fun LinkedHashMap.builderSize(): Int = size * 2
override fun LinkedHashMap.toResult(): Map = this
override fun Map.toBuilder(): LinkedHashMap = this as? LinkedHashMap ?: LinkedHashMap(this)
override fun LinkedHashMap.checkCapacity(size: Int) {}
override fun LinkedHashMap.insertKeyValuePair(index: Int, key: K, value: V): Unit = set(key, value)
}
@PublishedApi
internal class HashMapSerializer(
kSerializer: KSerializer, vSerializer: KSerializer
) : MapLikeSerializer, HashMap>(kSerializer, vSerializer) {
override val descriptor: SerialDescriptor = HashMapClassDesc(kSerializer.descriptor, vSerializer.descriptor)
override fun Map.collectionSize(): Int = size
override fun Map.collectionIterator(): Iterator> = iterator()
override fun builder(): HashMap = HashMap()
override fun HashMap.builderSize(): Int = size * 2
override fun HashMap.toResult(): Map = this
override fun Map.toBuilder(): HashMap = this as? HashMap ?: HashMap(this)
override fun HashMap.checkCapacity(size: Int) {}
override fun HashMap.insertKeyValuePair(index: Int, key: K, value: V): Unit = set(key, value)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy