commonMain.kotlinx.serialization.internal.PluginGeneratedSerialDescriptor.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-serialization-runtime Show documentation
Show all versions of kotlinx-serialization-runtime 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("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE", "UNUSED")
package kotlinx.serialization.internal
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.CompositeDecoder.Companion.UNKNOWN_NAME
/**
* Implementation that plugin uses to implement descriptors for auto-generated serializers.
*/
@PublishedApi
internal open class PluginGeneratedSerialDescriptor(
override val serialName: String,
private val generatedSerializer: GeneratedSerializer<*>? = null,
final override val elementsCount: Int
) : SerialDescriptor {
override val kind: SerialKind get() = StructureKind.CLASS
override val annotations: List get() = classAnnotations ?: emptyList()
private var added = -1
private val names = Array(elementsCount) { "[UNINITIALIZED]" }
private val propertiesAnnotations = arrayOfNulls?>(elementsCount)
// Classes rarely have annotations, so we can save up a bit of allocations here
private var classAnnotations: MutableList? = null
private var elementsOptionality = BooleanArray(elementsCount)
internal val namesSet: Set get() = indices.keys
// don't change lazy mode: KT-32871, KT-32872
private val indices: Map by lazy { buildIndices() }
// Lazy because of JS specific initialization order (#789)
private val typeParameterDescriptors: Array by lazy {
generatedSerializer?.typeParametersSerializers()?.map { it.descriptor }.compactArray()
}
// Can be without synchronization but Native will likely break due to freezing
private val _hashCode: Int by lazy { hashCodeImpl(typeParameterDescriptors) }
public fun addElement(name: String, isOptional: Boolean = false) {
names[++added] = name
elementsOptionality[added] = isOptional
propertiesAnnotations[added] = null
}
public fun pushAnnotation(annotation: Annotation) {
val list = propertiesAnnotations[added].let {
if (it == null) {
val result = ArrayList(1)
propertiesAnnotations[added] = result
result
} else {
it
}
}
list.add(annotation)
}
public fun pushClassAnnotation(a: Annotation) {
if (classAnnotations == null) {
classAnnotations = ArrayList(1)
}
classAnnotations!!.add(a)
}
override fun getElementDescriptor(index: Int): SerialDescriptor {
return generatedSerializer?.childSerializers()?.get(index)?.descriptor
?: throw IndexOutOfBoundsException("$serialName descriptor has only $elementsCount elements, index: $index")
}
override fun isElementOptional(index: Int): Boolean = elementsOptionality.getChecked(index)
override fun getElementAnnotations(index: Int): List =
propertiesAnnotations.getChecked(index) ?: emptyList()
override fun getElementName(index: Int): String = names.getChecked(index)
override fun getElementIndex(name: String): Int = indices[name] ?: UNKNOWN_NAME
private fun buildIndices(): Map {
val indices = HashMap()
for (i in names.indices) {
indices[names[i]] = i
}
return indices
}
override fun equals(other: Any?): Boolean = equalsImpl(other) { otherDescriptor ->
typeParameterDescriptors.contentEquals(otherDescriptor.typeParameterDescriptors)
}
override fun hashCode(): Int = _hashCode
override fun toString(): String {
return indices.entries.joinToString(", ", "$serialName(", ")") {
it.key + ": " + getElementDescriptor(it.value).serialName
}
}
}
internal inline fun SD.equalsImpl(
other: Any?,
typeParamsAreEqual: (otherDescriptor: SD) -> Boolean
): Boolean {
if (this === other) return true
if (other !is SD) return false
if (serialName != other.serialName) return false
if (!typeParamsAreEqual(other)) return false
if (this.elementsCount != other.elementsCount) return false
for (index in 0 until elementsCount) {
if (getElementDescriptor(index).serialName != other.getElementDescriptor(index).serialName) return false
if (getElementDescriptor(index).kind != other.getElementDescriptor(index).kind) return false
}
return true
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun SerialDescriptor.hashCodeImpl(typeParams: Array): Int {
var result = serialName.hashCode()
result = 31 * result + typeParams.contentHashCode()
val elementDescriptors = elementDescriptors
val namesHash = elementDescriptors.elementsHashCodeBy { it.serialName }
val kindHash = elementDescriptors.elementsHashCodeBy { it.kind }
result = 31 * result + namesHash
result = 31 * result + kindHash
return result
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy