/* * 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) }