decodeElementIndex
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.