decodeElementIndex

abstract fun decodeElementIndex(descriptor: SerialDescriptor): Int(source)

Decodes the index of the next element to be decoded. Index represents a position of the current element in the serial descriptor element that can be found with SerialDescriptor.getElementIndex.

If this method returns non-negative index, the caller should call one of the decode*Element methods with a resulting index. Apart from positive values, this method can return DECODE_DONE to indicate that no more elements are left or UNKNOWN_NAME to indicate that symbol with an unknown name was encountered.

Example of usage:

class MyPair(i: Int, d: Double)

object MyPairSerializer : KSerializer<MyPair> {
// ... other methods omitted

fun deserialize(decoder: Decoder): MyPair {
val composite = decoder.beginStructure(descriptor)
var i: Int? = null
var d: Double? = null
while (true) {
when (val index = composite.decodeElementIndex(descriptor)) {
0 -> i = composite.decodeIntElement(descriptor, 0)
1 -> d = composite.decodeDoubleElement(descriptor, 1)
DECODE_DONE -> break // Input is over
else -> error("Unexpected index: $index)
}
}
composite.endStructure(descriptor)
require(i != null && d != null)
return MyPair(i, d)
}
}

This example is a rough equivalent of what serialization plugin generates for serializable pair class.

The need in such a loop comes from unstructured nature of most serialization formats. For example, JSON for the following input {"d": 2.0, "i": 1}, will first read d key with index 1 and only after i with the index 0.

A potential implementation of this method for JSON format can be the following:

fun decodeElementIndex(descriptor: SerialDescriptor): Int {
// Ignore arrays
val nextKey: String? = myStringJsonParser.nextKey()
if (nextKey == null) return DECODE_DONE
return descriptor.getElementIndex(nextKey) // getElementIndex can return UNKNOWN_NAME
}

If decodeSequentially returns true, the caller might skip calling this method.