summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt10
-rw-r--r--formats/config/src/main/kotlin/org/jetbrains/kotlinx/serialization/config/ConfigReader.kt24
-rw-r--r--formats/properties/commonMain/src/kotlinx/serialization/Properties.kt8
-rw-r--r--formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoBuf.kt19
-rw-r--r--formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoTypes.kt6
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/ContextSerializer.kt2
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/Decoding.kt47
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/ElementWise.kt11
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/Encoding.kt37
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/KSerializer.kt12
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/SerialDescriptor.kt5
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt21
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt33
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/Tagged.kt40
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/internal/Arrays.common.kt8
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/internal/Enums.kt3
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/internal/ObjectSerializer.kt6
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.kt4
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/internal/Primitives.kt5
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/json/JsonElementSerializer.kt6
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/json/internal/TreeJsonInput.kt19
-rw-r--r--runtime/commonTest/src/kotlinx/serialization/SerialDescriptorBuilderTest.kt13
-rw-r--r--runtime/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt4
-rw-r--r--runtime/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt2
24 files changed, 185 insertions, 160 deletions
diff --git a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
index 654acd10..48e0f580 100644
--- a/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
+++ b/formats/cbor/commonMain/src/kotlinx/serialization/cbor/Cbor.kt
@@ -21,7 +21,7 @@ class Cbor(val updateMode: UpdateMode = UpdateMode.BANNED, val encodeDefaults: B
private open inner class CborListWriter(encoder: CborEncoder) : CborWriter(encoder) {
override fun writeBeginToken() = encoder.startArray()
- override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean = true
+ override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean = true
}
// Writes class as map [fieldName, fieldValue]
@@ -46,8 +46,8 @@ class Cbor(val updateMode: UpdateMode = UpdateMode.BANNED, val encodeDefaults: B
override fun endStructure(descriptor: SerialDescriptor) = encoder.end()
- override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
- val name = desc.getElementName(index)
+ override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
+ val name = descriptor.getElementName(index)
encoder.encodeString(name)
return true
}
@@ -176,8 +176,8 @@ class Cbor(val updateMode: UpdateMode = UpdateMode.BANNED, val encodeDefaults: B
protected open fun skipBeginToken() = setSize(decoder.startMap())
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
- val re = when (desc.kind) {
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ val re = when (descriptor.kind) {
StructureKind.LIST, is PolymorphicKind -> CborListReader(decoder)
StructureKind.MAP -> CborMapReader(decoder)
else -> CborReader(decoder)
diff --git a/formats/config/src/main/kotlin/org/jetbrains/kotlinx/serialization/config/ConfigReader.kt b/formats/config/src/main/kotlin/org/jetbrains/kotlinx/serialization/config/ConfigReader.kt
index 8a0eb794..693341af 100644
--- a/formats/config/src/main/kotlin/org/jetbrains/kotlinx/serialization/config/ConfigReader.kt
+++ b/formats/config/src/main/kotlin/org/jetbrains/kotlinx/serialization/config/ConfigReader.kt
@@ -89,11 +89,11 @@ class ConfigParser(context: SerialModule = EmptyModule): AbstractSerialFormat(co
return !conf.getIsNull(tag)
}
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
when {
- desc.kind.listLike -> ListConfigReader(conf.getList(currentTag))
- desc.kind.objLike -> if (ind > -1) ConfigReader(conf.getConfig(currentTag)) else this
- desc.kind == StructureKind.MAP -> MapConfigReader(conf.getObject(currentTag))
+ descriptor.kind.listLike -> ListConfigReader(conf.getList(currentTag))
+ descriptor.kind.objLike -> if (ind > -1) ConfigReader(conf.getConfig(currentTag)) else this
+ descriptor.kind == StructureKind.MAP -> MapConfigReader(conf.getObject(currentTag))
else -> this
}
}
@@ -101,11 +101,11 @@ class ConfigParser(context: SerialModule = EmptyModule): AbstractSerialFormat(co
private inner class ListConfigReader(private val list: ConfigList) : ConfigConverter<Int>() {
private var ind = -1
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
when {
- desc.kind.listLike -> ListConfigReader(list[currentTag] as ConfigList)
- desc.kind.objLike -> ConfigReader((list[currentTag] as ConfigObject).toConfig())
- desc.kind == StructureKind.MAP -> MapConfigReader(list[currentTag] as ConfigObject)
+ descriptor.kind.listLike -> ListConfigReader(list[currentTag] as ConfigList)
+ descriptor.kind.objLike -> ConfigReader((list[currentTag] as ConfigObject).toConfig())
+ descriptor.kind == StructureKind.MAP -> MapConfigReader(list[currentTag] as ConfigObject)
else -> this
}
@@ -133,11 +133,11 @@ class ConfigParser(context: SerialModule = EmptyModule): AbstractSerialFormat(co
private val indexSize = values.size * 2
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
when {
- desc.kind.listLike -> ListConfigReader(values[currentTag / 2] as ConfigList)
- desc.kind.objLike -> ConfigReader((values[currentTag / 2] as ConfigObject).toConfig())
- desc.kind == StructureKind.MAP -> MapConfigReader(values[currentTag / 2] as ConfigObject)
+ descriptor.kind.listLike -> ListConfigReader(values[currentTag / 2] as ConfigList)
+ descriptor.kind.objLike -> ConfigReader((values[currentTag / 2] as ConfigObject).toConfig())
+ descriptor.kind == StructureKind.MAP -> MapConfigReader(values[currentTag / 2] as ConfigObject)
else -> this
}
diff --git a/formats/properties/commonMain/src/kotlinx/serialization/Properties.kt b/formats/properties/commonMain/src/kotlinx/serialization/Properties.kt
index 2e9a2030..c60d28f7 100644
--- a/formats/properties/commonMain/src/kotlinx/serialization/Properties.kt
+++ b/formats/properties/commonMain/src/kotlinx/serialization/Properties.kt
@@ -93,11 +93,11 @@ public class Properties(context: SerialModule = EmptyModule) : AbstractSerialFor
private var currentIndex = 0
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
return InMapper(map).also { copyTagsTo(it) }
}
- override fun decodeCollectionSize(desc: SerialDescriptor): Int {
+ override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
return decodeTaggedInt(nested("size"))
}
@@ -121,11 +121,11 @@ public class Properties(context: SerialModule = EmptyModule) : AbstractSerialFor
private var currentIndex = 0
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
return InNullableMapper(map).also { copyTagsTo(it) }
}
- override fun decodeCollectionSize(desc: SerialDescriptor): Int {
+ override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
return decodeTaggedInt(nested("size"))
}
diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoBuf.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoBuf.kt
index 03867447..f703e2b9 100644
--- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoBuf.kt
+++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoBuf.kt
@@ -149,7 +149,7 @@ class ProtoBuf(
val parentTag: ProtoDesc?, private val parentEncoder: ProtobufEncoder,
private val stream: ByteArrayOutputStream = ByteArrayOutputStream()
) : ProtobufWriter(ProtobufEncoder(stream)) {
- override fun endEncode(desc: SerialDescriptor) {
+ override fun endEncode(descriptor: SerialDescriptor) {
if (parentTag != null) {
parentEncoder.writeBytes(stream.toByteArray(), parentTag.first)
} else {
@@ -243,12 +243,17 @@ class ProtoBuf(
).first == serialId
} ?: -1
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder = when (desc.kind) {
- StructureKind.LIST -> RepeatedReader(decoder, currentTag)
- StructureKind.CLASS, StructureKind.OBJECT, is PolymorphicKind ->
- ProtobufReader(makeDelimited(decoder, currentTagOrNull))
- StructureKind.MAP -> MapEntryReader(makeDelimited(decoder, currentTagOrNull), currentTagOrNull)
- else -> throw SerializationException("Primitives are not supported at top-level")
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder =
+ when (descriptor.kind) {
+ StructureKind.LIST -> RepeatedReader(decoder, currentTag)
+ StructureKind.CLASS, StructureKind.OBJECT, is PolymorphicKind ->
+ ProtobufReader(makeDelimited(decoder, currentTagOrNull))
+ StructureKind.MAP -> MapEntryReader(makeDelimited(decoder, currentTagOrNull), currentTagOrNull)
+ else -> throw SerializationException("Primitives are not supported at top-level")
+ }
+
+ override fun endStructure(descriptor: SerialDescriptor) {
+ // Nothing
}
override fun decodeTaggedBoolean(tag: ProtoDesc): Boolean = when (val i = decoder.nextInt(ProtoNumberType.DEFAULT)) {
diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoTypes.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoTypes.kt
index c7bc1463..c5369b08 100644
--- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoTypes.kt
+++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/ProtoTypes.kt
@@ -16,9 +16,9 @@ public annotation class ProtoType(val type: ProtoNumberType)
internal typealias ProtoDesc = Pair<Int, ProtoNumberType>
-internal fun extractParameters(desc: SerialDescriptor, index: Int, zeroBasedDefault: Boolean = false): ProtoDesc {
- val idx = getProtoId(desc, index) ?: (if (zeroBasedDefault) index else index + 1)
- val format = desc.findAnnotation<ProtoType>(index)?.type
+internal fun extractParameters(descriptor: SerialDescriptor, index: Int, zeroBasedDefault: Boolean = false): ProtoDesc {
+ val idx = getProtoId(descriptor, index) ?: (if (zeroBasedDefault) index else index + 1)
+ val format = descriptor.findAnnotation<ProtoType>(index)?.type
?: ProtoNumberType.DEFAULT
return idx to format
}
diff --git a/runtime/commonMain/src/kotlinx/serialization/ContextSerializer.kt b/runtime/commonMain/src/kotlinx/serialization/ContextSerializer.kt
index 28b84159..f182aaa1 100644
--- a/runtime/commonMain/src/kotlinx/serialization/ContextSerializer.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/ContextSerializer.kt
@@ -23,7 +23,7 @@ import kotlin.reflect.*
*/
@ImplicitReflectionSerializer
public class ContextSerializer<T : Any>(private val serializableClass: KClass<T>) : KSerializer<T> {
- public override val descriptor: SerialDescriptor = SerialDescriptor("kotlinx.serialization.ContextSerializer", UnionKind.CONTEXTUAL) {}
+ public override val descriptor: SerialDescriptor = SerialDescriptor("kotlinx.serialization.ContextSerializer", UnionKind.CONTEXTUAL)
public override fun serialize(encoder: Encoder, value: T) {
val serializer = encoder.context.getContextualOrDefault(value)
diff --git a/runtime/commonMain/src/kotlinx/serialization/Decoding.kt b/runtime/commonMain/src/kotlinx/serialization/Decoding.kt
index 9d01990a..796bccbc 100644
--- a/runtime/commonMain/src/kotlinx/serialization/Decoding.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/Decoding.kt
@@ -8,19 +8,19 @@ import kotlinx.serialization.modules.*
/**
* Decoder is a core deserialization primitive that encapsulates the knowledge of the underlying
- * format and its storage, exposing only structural methods to the deserializer, making it completely
+ * format and an underlying storage, exposing only structural methods to the deserializer, making it completely
* format-agnostic. Deserialization process takes a decoder and asks him for a sequence of primitive elements,
- * defined by a deserializer serial form, while decoder knows hot to retrieve these primitive elements from an actual format
+ * defined by a deserializer serial form, while decoder knows how to retrieve these primitive elements from an actual format
* representations.
*
* Decoder provides high-level API that operates with basic primitive types, collections
- * and nested structures. Internally, decoder represents input storage and operates with its state
+ * and nested structures. Internally, the decoder represents input storage, and operates with its state
* and lower level format-specific details.
*
* To be more specific, serialization asks a decoder for a sequence of "give me an int, give me
* a double, give me a list of strings and give me another object that is a nested int", while decoding
* transforms this sequence into a format-specific commands such as "parse the part of the string until the next quotation mark
- * as an int to retrieve an int, parse everything withing the next curly braces to retrieve elements of a nested object etc."
+ * as an int to retrieve an int, parse everything within the next curly braces to retrieve elements of a nested object etc."
*
* The symmetric interface for the serialization process is [Encoder].
*
@@ -46,7 +46,7 @@ import kotlinx.serialization.modules.*
* ```
*
* E.g. if the decoder belongs to JSON format, then [beginStructure] will parse an opening bracket
- * (`{` or `[`, depending on the descriptor kind), returning the [CompositeDecoder] that is aware of semicolon separator,
+ * (`{` or `[`, depending on the descriptor kind), returning the [CompositeDecoder] that is aware of colon separator,
* that should be read after each key-value pair, whilst [CompositeDecoder.endStructure] will parse a closing bracket.
*
* ### Exception guarantees.
@@ -78,7 +78,7 @@ import kotlinx.serialization.modules.*
*
* This deserializer does not know anything about the underlying data and will work with any properly-implemented decoder.
* JSON, for example, parses an opening bracket `{` during the `beginStructure` call, checks that the next key
- * after this bracket is `stringValue` (using the descriptor), returns the value after the semicolon as string value
+ * after this bracket is `stringValue` (using the descriptor), returns the value after the colon as string value
* and parses closing bracket `}` during the `endStructure`.
* XML would do the roughly the same, but with different separators and parsing structures, while ProtoBuf
* machinery could be completely different.
@@ -125,7 +125,7 @@ public interface Decoder {
public fun decodeNotNullMark(): Boolean
/**
- * Parses the `null` value and returns it.
+ * Decodes the `null` value and returns it.
*/
public fun decodeNull(): Nothing?
@@ -140,7 +140,7 @@ public interface Decoder {
/**
* Decodes a single byte value.
- * Corresponding kind is [PrimitiveKind.BOOLEAN].
+ * Corresponding kind is [PrimitiveKind.BYTE].
*/
public fun decodeByte(): Byte
@@ -152,18 +152,18 @@ public interface Decoder {
/**
* Decodes a 16-bit unicode character value.
- * Corresponding kind is [PrimitiveKind.BOOLEAN].
+ * Corresponding kind is [PrimitiveKind.CHAR].
*/
public fun decodeChar(): Char
/**
- * Decodes a 32-bit int value
+ * Decodes a 32-bit integer value.
* Corresponding kind is [PrimitiveKind.INT].
*/
public fun decodeInt(): Int
/**
- * Decodes a 64-bit long value.
+ * Decodes a 64-bit integer value.
* Corresponding kind is [PrimitiveKind.LONG].
*/
public fun decodeLong(): Long
@@ -194,7 +194,7 @@ public interface Decoder {
* underlying input "C", [decodeEnum] method should return `2` as a result.
*
* This method does not imply any restrictions on the input format,
- * the format is free to store the enum by its name, index, ordinal or any other
+ * the format is free to store the enum by its name, index, ordinal or any other enum representation.
*/
public fun decodeEnum(enumDescriptor: SerialDescriptor): Int
@@ -214,7 +214,7 @@ public interface Decoder {
* ```
* has three nested structures: the very beginning of the data, "b" value and "c" value.
*/
- public fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder
+ public fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder
/**
* Decodes the value of type [T] by delegating the decoding process to the given [deserializer].
@@ -258,10 +258,7 @@ public interface Decoder {
* Please refer to [decodeElementIndex] for example of such loop.
*
* All `decode*` methods have `index` and `serialDescriptor` parameters with a strict semantics and constraints:
- * * `descriptor` is always the same as one used in [Decoder.beginStructure]. While this parameter may seem redundant,
- * it is required for efficient serialization process to avoid excessive field spilling.
- * If you are writing your own format, you can safely ignore this parameter and use one used in `beginStructure`
- * for simplicity.
+ * * `descriptor` argument is always the same as one used in [Decoder.beginStructure].
* * `index` of the element being decoded. For [sequential][decodeSequentially] decoding, it is always a monotonic
* sequence from `0` to `descriptor.elementsCount` and for indexing-loop it is always an index that [decodeElementIndex]
* has returned from the last call.
@@ -309,9 +306,7 @@ public interface CompositeDecoder {
* For example, composite decoder of JSON format will expect (and parse)
* a closing bracket in the underlying input.
*/
- public fun endStructure(descriptor: SerialDescriptor) {
- // TODO get rid of default implementation, method is too important
- }
+ public fun endStructure(descriptor: SerialDescriptor)
/**
* Checks whether the current decoder supports strictly ordered decoding of the data
@@ -403,8 +398,8 @@ public interface CompositeDecoder {
* fun decodeElementIndex(descriptor: SerialDescriptor): Int {
* // Ignore arrays
* val nextKey: String? = myStringJsonParser.nextKey()
- * if (nextObjectKey == null) return READ_DONE
- * return descriptor.getElementIndex(nextKey) // getElementIndex can return UNKNOWN_FIELD
+ * if (nextKey == null) return READ_DONE
+ * return descriptor.getElementIndex(nextKey) // getElementIndex can return UNKNOWN_NAME
* }
* ```
*/
@@ -454,10 +449,10 @@ public interface CompositeDecoder {
* The resulting value is associated with the [descriptor] element at the given [index].
* The element at the given index should have [PrimitiveKind.INT] kind.
*/
- public fun decodeIntElement(desc: SerialDescriptor, index: Int): Int
+ public fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int
/**
- * Decodes a 32-bit long value from the underlying input.
+ * Decodes a 64-bit integer value from the underlying input.
* The resulting value is associated with the [descriptor] element at the given [index].
* The element at the given index should have [PrimitiveKind.LONG] kind.
*/
@@ -473,7 +468,7 @@ public interface CompositeDecoder {
/**
* Decodes a 64-bit IEEE 754 floating point value from the underlying input.
* The resulting value is associated with the [descriptor] element at the given [index].
- * The element at the given index should have [PrimitiveKind.LONG] kind.
+ * The element at the given index should have [PrimitiveKind.DOUBLE] kind.
*/
public fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double
@@ -512,7 +507,7 @@ public interface CompositeDecoder {
// Not documented
public fun <T : Any> updateNullableSerializableElement(
- desc: SerialDescriptor,
+ descriptor: SerialDescriptor,
index: Int,
deserializer: DeserializationStrategy<T?>,
old: T?
diff --git a/runtime/commonMain/src/kotlinx/serialization/ElementWise.kt b/runtime/commonMain/src/kotlinx/serialization/ElementWise.kt
index b41b6137..57fe8bed 100644
--- a/runtime/commonMain/src/kotlinx/serialization/ElementWise.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/ElementWise.kt
@@ -22,12 +22,6 @@ abstract class ElementValueEncoder : Encoder, CompositeEncoder {
*/
open fun encodeElement(desc: SerialDescriptor, index: Int): Boolean = true
- /**
- * Encodes that following value is not null.
- * No-op by default.
- */
- override fun encodeNotNullMark() {}
-
open fun encodeValue(value: Any): Unit
= throw SerializationException("Non-serializable ${value::class} is not supported by ${this::class} encoder")
@@ -52,8 +46,6 @@ abstract class ElementValueEncoder : Encoder, CompositeEncoder {
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = encodeValue(index)
// Delegating implementation of CompositeEncoder
-
- final override fun encodeNonSerializableElement(descriptor: SerialDescriptor, index: Int, value: Any) { if (encodeElement(descriptor, index)) encodeValue(value) }
final override fun encodeUnitElement(descriptor: SerialDescriptor, index: Int) { if (encodeElement(descriptor, index)) encodeUnit() }
final override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) { if (encodeElement(descriptor, index)) encodeBoolean(value) }
final override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte) { if (encodeElement(descriptor, index)) encodeByte(value) }
@@ -109,6 +101,9 @@ abstract class ElementValueDecoder : Decoder, CompositeDecoder {
return this
}
+ override fun endStructure(descriptor: SerialDescriptor) {
+ }
+
final override fun decodeUnitElement(desc: SerialDescriptor, index: Int) = decodeUnit()
final override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean = decodeBoolean()
final override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte = decodeByte()
diff --git a/runtime/commonMain/src/kotlinx/serialization/Encoding.kt b/runtime/commonMain/src/kotlinx/serialization/Encoding.kt
index c33b6c69..979f28bd 100644
--- a/runtime/commonMain/src/kotlinx/serialization/Encoding.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/Encoding.kt
@@ -20,7 +20,7 @@ import kotlinx.serialization.modules.*
* To be more specific, serialization transforms a value into a sequence of "here is an int, here is
* a double, here a list of strings and here is another object that is a nested int", while encoding
* transforms this sequence into a format-specific commands such as "insert opening curly bracket
- * for a nested object start, insert a name of the value and the value separated with semicolon for an int etc."
+ * for a nested object start, insert a name of the value and the value separated with colon for an int etc."
*
* The symmetric interface for the deserialization process is [Decoder].
*
@@ -45,7 +45,7 @@ import kotlinx.serialization.modules.*
* ```
*
* E.g. if the encoder belongs to JSON format, then [beginStructure] will write an opening bracket
- * (`{` or `[`, depending on the descriptor kind), returning the [CompositeEncoder] that is aware of semicolon separator,
+ * (`{` or `[`, depending on the descriptor kind), returning the [CompositeEncoder] that is aware of colon separator,
* that should be appended between each key-value pair, whilst [CompositeEncoder.endStructure] will write a closing bracket.
*
* ### Exception guarantees.
@@ -118,7 +118,7 @@ public interface Encoder {
* This method has a use in highly-performant binary formats and can
* be safely ignore by most of the regular formats.
*/
- public fun encodeNotNullMark()
+ public fun encodeNotNullMark() {}
/**
* Encodes `null` value.
@@ -136,7 +136,7 @@ public interface Encoder {
/**
* Encodes a single byte value.
- * Corresponding kind is [PrimitiveKind.BOOLEAN].
+ * Corresponding kind is [PrimitiveKind.BYTE].
*/
public fun encodeByte(value: Byte)
@@ -148,19 +148,19 @@ public interface Encoder {
/**
* Encodes a 16-bit unicode character value.
- * Corresponding kind is [PrimitiveKind.BOOLEAN].
+ * Corresponding kind is [PrimitiveKind.CHAR].
*/
public fun encodeChar(value: Char)
/**
- * Encodes a 32-bit int value
+ * Encodes a 32-bit integer value.
* Corresponding kind is [PrimitiveKind.INT].
*/
public fun encodeInt(value: Int)
/**
- * Encodes a 64-bit int value
- * Corresponding kind is [PrimitiveKind.INT].
+ * Encodes a 64-bit integer value.
+ * Corresponding kind is [PrimitiveKind.LONG].
*/
public fun encodeLong(value: Long)
@@ -172,7 +172,7 @@ public interface Encoder {
/**
* Encodes a 64-bit IEEE 754 floating point value.
- * Corresponding kind is [PrimitiveKind.FLOAT].
+ * Corresponding kind is [PrimitiveKind.DOUBLE].
*/
public fun encodeDouble(value: Double)
@@ -221,7 +221,7 @@ public interface Encoder {
*
* // StringHolder serializer
* fun serialize(encoder: Encoder, value: StringHolder) {
- * val composite = encoder.beginStructure(descriptor) // One more '{' when the key "stringHolder" is already wriotten
+ * val composite = encoder.beginStructure(descriptor) // One more '{' when the key "stringHolder" is already written
* composite.encodeStringElement(descriptor, 0, value.stringValue) // Serialize actual value
* composite.endStructure(descriptor) // Closing bracket
* }
@@ -235,13 +235,13 @@ public interface Encoder {
/**
* Encodes the beginning of the collection with size [collectionSize] and the given serializer of its type parameters.
+ * This method has to be implemented only if you need to know collection size in advance, otherwise, [beginStructure] can be used.
*/
public fun beginCollection(
descriptor: SerialDescriptor,
collectionSize: Int,
vararg typeSerializers: KSerializer<*>
- ): CompositeEncoder =
- beginStructure(descriptor, *typeSerializers)
+ ): CompositeEncoder = beginStructure(descriptor, *typeSerializers)
/**
* Encodes the [value] of type [T] by delegating the encoding process to the given [serializer].
@@ -271,7 +271,6 @@ public interface Encoder {
*
* All `encode*` methods have `index` and `serialDescriptor` parameters with a strict semantics and constraints:
* * `descriptor` is always the same as one used in [Encoder.beginStructure]. While this parameter may seem redundant,
- * * `descriptor` is always the same as one used in [Encoder.beginStructure]. While this parameter may seem redundant,
* it is required for efficient serialization process to avoid excessive field spilling.
* If you are writing your own format, you can safely ignore this parameter and use one used in `beginStructure`
* for simplicity.
@@ -292,9 +291,7 @@ public interface CompositeEncoder {
* For example, composite encoder of JSON format will write
* a closing bracket in the underlying input and reduce the number of nesting for pretty printing.
*/
- public fun endStructure(descriptor: SerialDescriptor) {
- // TODO get rid of default implementation, method is too important
- }
+ public fun endStructure(descriptor: SerialDescriptor)
/**
* Whether the format should encode values that are equal to the default values.
@@ -390,8 +387,12 @@ public interface CompositeEncoder {
value: T?
)
- // No idea
- public fun encodeNonSerializableElement(descriptor: SerialDescriptor, index: Int, value: Any)
+ @Deprecated(
+ level = DeprecationLevel.ERROR,
+ message = "This method is deprecated for removal. Please remove it from your implementation and delegate to default method instead"
+ )
+ public fun encodeNonSerializableElement(descriptor: SerialDescriptor, index: Int, value: Any) {
+ }
}
/**
diff --git a/runtime/commonMain/src/kotlinx/serialization/KSerializer.kt b/runtime/commonMain/src/kotlinx/serialization/KSerializer.kt
index 6c4811b4..0f31bebe 100644
--- a/runtime/commonMain/src/kotlinx/serialization/KSerializer.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/KSerializer.kt
@@ -11,14 +11,14 @@ package kotlinx.serialization
*
* Serialization is decoupled from the encoding process to make it completely format-agnostic.
* Serialization represents a type as its serial form and is abstracted from the actual
- * format (whether its JSON, ProtoBuf or a hashing) and is not aware of the underlying storage
+ * format (whether its JSON, ProtoBuf or a hashing) and unaware of the underlying storage
* (whether it is a string builder, byte array or a network socket), while
* encoding/decoding is abstracted from a particular type and its serial form and is responsible
* for transforming primitives ("here in an int property 'foo'" call from a serializer) into a particular
* format-specific representation ("for a given int, append a property name in quotation marks,
- * then append a semicolon, then append an actual value" for JSON) and how to retrieve a primitive
+ * then append a colon, then append an actual value" for JSON) and how to retrieve a primitive
* ("give me an int that is 'foo' property") from the underlying representation ("expect the next string to be 'foo',
- * parse it, then parse semicolon, then parse a string until the next comma as an int an return it).
+ * parse it, then parse colon, then parse a string until the next comma as an int and return it).
*
* Serial form consists of a structural description, declared by the [descriptor] and
* actual serialization and deserialization processes, defined by the corresponding
@@ -54,9 +54,9 @@ public interface KSerializer<T> : SerializationStrategy<T>, DeserializationStrat
* the shape of the serialized form (e.g. what elements are encoded as lists and what as primitives)
* along with its metadata such as alternative names.
*
- * The descriptor is used dynamically, during serialization by encoders and decoders
- * to introspect the type and metadata of [T]'s elements being encoded or decoded and
- * statically, to introspect the type, infer the schema or to compare against the predefined schema.
+ * The descriptor is used during serialization by encoders and decoders
+ * to introspect the type and metadata of [T]'s elements being encoded or decoded, and
+ * to introspect the type, infer the schema or to compare against the predefined schema.
*/
override val descriptor: SerialDescriptor
diff --git a/runtime/commonMain/src/kotlinx/serialization/SerialDescriptor.kt b/runtime/commonMain/src/kotlinx/serialization/SerialDescriptor.kt
index ab1ae5af..5c517f27 100644
--- a/runtime/commonMain/src/kotlinx/serialization/SerialDescriptor.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/SerialDescriptor.kt
@@ -71,12 +71,15 @@ package kotlinx.serialization
* )
*
* // Descriptor for such class:
- * SerialDescriptor("my.package.Data", 3) {
+ * SerialDescriptor("my.package.Data") {
* // intField is deliberately ignored by serializer -- not present in the descriptor as well
* element<Long>("_longField") // longField is named as _longField
* element("stringField", listDescriptor<String>())
* }
* ```
+ *
+ * For a classes that are represented as a single primitive value,
+ * [PrimitiveDescriptor] builder function can be used instead.
*/
public interface SerialDescriptor {
/**
diff --git a/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt b/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt
index 7d40e369..cf290132 100644
--- a/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt
@@ -10,9 +10,6 @@ import kotlinx.serialization.internal.*
* Builder for [SerialDescriptor].
* The resulting descriptor will be uniquely identified by the given [serialName],
* with the corresponding [kind] and structure described in [builder] function.
- * The count of descriptor elements should be known in advance to make API less error-prone,
- * and this builder will throw [IllegalStateException] if count of added elements will be
- * lesser or greater than [elementsCount].
*
* Example:
* ```
@@ -24,7 +21,7 @@ import kotlinx.serialization.internal.*
* val nullableInt: Int?
* )
* // Descriptor for such class:
- * SerialDescriptor("my.package.Data", 3) {
+ * SerialDescriptor("my.package.Data") {
* // intField is deliberately ignored by serializer -- not present in the descriptor as well
* element<Long>("_longField") // longField is named as _longField
* element("stringField", listDescriptor<String>())
@@ -36,6 +33,7 @@ public fun SerialDescriptor(
kind: SerialKind = StructureKind.CLASS,
builder: SerialDescriptorBuilder.() -> Unit = {}
): SerialDescriptor {
+ require(serialName.isNotBlank()) { "Blank serial names are prohibited" }
val sdBuilder = SerialDescriptorBuilder(serialName)
sdBuilder.builder()
return SerialDescriptorImpl(serialName, kind, sdBuilder.elementNames.size, sdBuilder)
@@ -49,7 +47,7 @@ public fun SerialDescriptor(
* override val descriptor: SerialDescriptor =
* PrimitiveDescriptor("kotlinx.serialization.LongAsStringSerializer", PrimitiveKind.STRING)
*
- * override fun serialize(encoder: Encoder, obj: Long) {
+ * override fun serialize(encoder: Encoder, value: Long) {
* encoder.encodeString(obj.toString())
* }
*
@@ -59,7 +57,10 @@ public fun SerialDescriptor(
* }
* ```
*/
-public fun PrimitiveDescriptor(serialName: String, kind: PrimitiveKind): SerialDescriptor = PrimitiveDescriptorSafe(serialName, kind)
+public fun PrimitiveDescriptor(serialName: String, kind: PrimitiveKind): SerialDescriptor {
+ require(serialName.isNotBlank()) { "Blank serial names are prohibited" }
+ return PrimitiveDescriptorSafe(serialName, kind)
+}
/**
* Returns new serial descriptor for the same type with [isNullable][SerialDescriptor.isNullable]
@@ -112,7 +113,7 @@ public class SerialDescriptorBuilder internal constructor(
* )
*
* // Corresponding descriptor
- * SerialDescriptor("package.Data", 2) {
+ * SerialDescriptor("package.Data") {
* element<Int?>("intField", isOptional = true)
* element<Long>("longField", annotations = listOf(protoIdAnnotationInstance))
* }
@@ -124,9 +125,7 @@ public class SerialDescriptorBuilder internal constructor(
annotations: List<Annotation> = emptyList(),
isOptional: Boolean = false
) {
- if (!uniqueNames.add(elementName)) {
- error("Element with name '$elementName' is already registered")
- }
+ require(uniqueNames.add(elementName)) { "Element with name '$elementName' is already registered" }
elementNames += elementName
elementDescriptors += descriptor
elementAnnotations += annotations
@@ -135,7 +134,7 @@ public class SerialDescriptorBuilder internal constructor(
/**
* Reified version of [element] function that
- * extract descriptor using `serializer<T>().descriptor` call with the all the restrictions of `serializer<T>().descriptor`.
+ * extract descriptor using `serializer<T>().descriptor` call with all the restrictions of `serializer<T>().descriptor`.
*/
@ImplicitReflectionSerializer
public inline fun <reified T> element(
diff --git a/runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt b/runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt
index 9301e83b..dc22dbbf 100644
--- a/runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt
@@ -13,8 +13,8 @@ package kotlinx.serialization
* depending on that, may write it as a plain value for primitive kinds, open a
* curly brace '{' for class-like structures and square bracket '[' for list- and array- like structures.
*
- * Kinds are used both in runtime, to serialize a value properly and statically,
- * to retrospect the type structure or build serialization schema.
+ * Kinds are used both during serialization, to serialize a value properly and statically, and
+ * to introspect the type structure or build serialization schema.
*
* Kind should match the structure of the serialized form, not the structure of the corresponding Kotlin class.
* Meaning that if serializable class `class IntPair(val left: Int, val right: Int)` is represented by the serializer
@@ -29,7 +29,7 @@ public sealed class SerialKind {
}
/**
- * Values of primitive kinds that usually are represented as a single value.
+ * Values of primitive kinds usually are represented as a single value.
* All default serializers for Kotlin [primitives types](https://kotlinlang.org/docs/tutorials/kotlin-for-py/primitive-data-types-and-their-limitations.html)
* and [String] have primitive kind.
*
@@ -40,7 +40,7 @@ public sealed class SerialKind {
* as a single [Int] value, a typical serializer will serialize its value in the following manner:
* ```
* val intValue = color.rgbToInt()
- * encoder.encodeInt()
+ * encoder.encodeInt(intValue)
* ```
* and a corresponding [Decoder] counterpart.
*
@@ -131,7 +131,7 @@ public sealed class PrimitiveKind : SerialKind() {
*
* ### Lists
* [LIST] represent a structure with potentially unknown in advance number of elements of the same type.
- * All standard serializable [List] implementors are represented as [LIST] kind of the same type.
+ * All standard serializable [List] implementors and arrays are represented as [LIST] kind of the same type.
*
* ### Maps
* [MAP] represent a structure with potentially unknown in advance number of key-value pairs of the same type.
@@ -149,7 +149,7 @@ public sealed class PrimitiveKind : SerialKind() {
* ```
* val composite = encoder.beginStructure(descriptor) // Denotes the start of the structure
* composite.encodeIntElement(descriptor, index = 0, holder.myValue)
- * composite.beginStructure(descriptor) // Denotes the end of the structure
+ * composite.endStructure(descriptor) // Denotes the end of the structure
* ```
* and its corresponding [Decoder] counterpart.
*
@@ -168,7 +168,7 @@ public sealed class StructureKind : SerialKind() {
public object CLASS : StructureKind()
/**
- * Structure kind for lists of an arbitrary length.
+ * Structure kind for lists and arrays of an arbitrary length.
* Serializers typically encode classes with calls to [Encoder.beginCollection] and [CompositeEncoder.endStructure],
* writing the elements of the list between these calls.
* Built-in list serializers treat elements as homogeneous, though application-specific serializers may impose
@@ -191,8 +191,8 @@ public sealed class StructureKind : SerialKind() {
public object MAP : StructureKind()
/**
- * Structure kind for singleton objects defined with `object` keyword with.
- * By default, objects are serialized as empty structures without any states and their identity is preserved
+ * Structure kind for singleton objects defined with `object` keyword.
+ * By default, objects are serialized as empty structures without any state and their identity is preserved
* across serialization within the same process, so you always have the same instance of the object.
*
* Empty structure is represented as a call to [Encoder.beginStructure] with the following [CompositeEncoder.endStructure]
@@ -211,9 +211,9 @@ public sealed class UnionKind : SerialKind() {
/**
* Represents a Kotlin [Enum] with statically known values.
* All enum values should be enumerated in descriptor elements.
- * Each element descriptor of a [Enum] kind represents an instance of a particular enum,
- * and each [positional name][SerialDescriptor.getElementName] contains a corresponding
- * enum element [name][Enum.name].
+ * Each element descriptor of a [Enum] kind represents an instance of a particular enum
+ * and has an [StructureKind.OBJECT] kind.
+ * Each [positional name][SerialDescriptor.getElementName] contains a corresponding enum element [name][Enum.name].
*
* Corresponding encoder and decoder methods are [Encoder.encodeEnum] and [Decoder.decodeEnum].
*/
@@ -225,6 +225,15 @@ public sealed class UnionKind : SerialKind() {
* be used for [contextual][ContextualSerialization] serialization.
*/
public object CONTEXTUAL : UnionKind()
+
+ companion object {
+ @Deprecated(
+ "Moved out from UnionKind to StructureKind.",
+ ReplaceWith("StructureKind.OBJECT"),
+ DeprecationLevel.ERROR
+ )
+ val OBJECT = StructureKind.OBJECT
+ }
}
/**
diff --git a/runtime/commonMain/src/kotlinx/serialization/Tagged.kt b/runtime/commonMain/src/kotlinx/serialization/Tagged.kt
index 928b05a6..5354ba6f 100644
--- a/runtime/commonMain/src/kotlinx/serialization/Tagged.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/Tagged.kt
@@ -85,9 +85,7 @@ abstract class TaggedEncoder<Tag : Any?> : Encoder, CompositeEncoder {
/**
* Format-specific replacement for [endStructure], because latter is overridden to manipulate tag stack.
*/
- open fun endEncode(desc: SerialDescriptor) {}
-
- final override fun encodeNonSerializableElement(descriptor: SerialDescriptor, index: Int, value: Any) = encodeTaggedValue(descriptor.getTag(index), value)
+ open fun endEncode(descriptor: SerialDescriptor) {}
final override fun encodeUnitElement(descriptor: SerialDescriptor, index: Int) = encodeTaggedUnit(descriptor.getTag(index))
final override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) = encodeTaggedBoolean(descriptor.getTag(index), value)
@@ -100,13 +98,13 @@ abstract class TaggedEncoder<Tag : Any?> : Encoder, CompositeEncoder {
final override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) = encodeTaggedChar(descriptor.getTag(index), value)
final override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) = encodeTaggedString(descriptor.getTag(index), value)
- final override fun <T : Any?> encodeSerializableElement(desc: SerialDescriptor, index: Int, serializer: SerializationStrategy<T>, value: T) {
- if (encodeElement(desc, index))
+ final override fun <T : Any?> encodeSerializableElement(descriptor: SerialDescriptor, index: Int, serializer: SerializationStrategy<T>, value: T) {
+ if (encodeElement(descriptor, index))
encodeSerializableValue(serializer, value)
}
- final override fun <T : Any> encodeNullableSerializableElement(desc: SerialDescriptor, index: Int, serializer: SerializationStrategy<T>, value: T?) {
- if (encodeElement(desc, index))
+ final override fun <T : Any> encodeNullableSerializableElement(descriptor: SerialDescriptor, index: Int, serializer: SerializationStrategy<T>, value: T?) {
+ if (encodeElement(descriptor, index))
encodeNullableSerializableValue(serializer, value)
}
@@ -182,32 +180,36 @@ abstract class TaggedDecoder<Tag : Any?> : Decoder, CompositeDecoder {
final override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeTaggedEnum(popTag(), enumDescriptor)
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
return this
}
- final override fun decodeUnitElement(desc: SerialDescriptor, index: Int) = decodeTaggedUnit(desc.getTag(index))
+ override fun endStructure(descriptor: SerialDescriptor) {
+ // Nothing
+ }
+
+ final override fun decodeUnitElement(descriptor: SerialDescriptor, index: Int) = decodeTaggedUnit(descriptor.getTag(index))
final override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean = decodeTaggedBoolean(descriptor.getTag(index))
final override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte = decodeTaggedByte(descriptor.getTag(index))
final override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short = decodeTaggedShort(descriptor.getTag(index))
- final override fun decodeIntElement(desc: SerialDescriptor, index: Int): Int = decodeTaggedInt(desc.getTag(index))
+ final override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int = decodeTaggedInt(descriptor.getTag(index))
final override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long = decodeTaggedLong(descriptor.getTag(index))
final override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float = decodeTaggedFloat(descriptor.getTag(index))
- final override fun decodeDoubleElement(desc: SerialDescriptor, index: Int): Double = decodeTaggedDouble(desc.getTag(index))
+ final override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double = decodeTaggedDouble(descriptor.getTag(index))
final override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char = decodeTaggedChar(descriptor.getTag(index))
final override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String = decodeTaggedString(descriptor.getTag(index))
- final override fun <T : Any?> decodeSerializableElement(desc: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>): T =
- tagBlock(desc.getTag(index)) { decodeSerializableValue(deserializer) }
+ final override fun <T : Any?> decodeSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>): T =
+ tagBlock(descriptor.getTag(index)) { decodeSerializableValue(deserializer) }
- final override fun <T : Any> decodeNullableSerializableElement(desc: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>): T? =
- tagBlock(desc.getTag(index)) { decodeNullableSerializableValue(deserializer) }
+ final override fun <T : Any> decodeNullableSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>): T? =
+ tagBlock(descriptor.getTag(index)) { decodeNullableSerializableValue(deserializer) }
- override fun <T> updateSerializableElement(desc: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, old: T): T =
- tagBlock(desc.getTag(index)) { updateSerializableValue(deserializer, old) }
+ override fun <T> updateSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, old: T): T =
+ tagBlock(descriptor.getTag(index)) { updateSerializableValue(deserializer, old) }
- override fun <T : Any> updateNullableSerializableElement(desc: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>, old: T?): T? =
- tagBlock(desc.getTag(index)) { updateNullableSerializableValue(deserializer, old) }
+ override fun <T : Any> updateNullableSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>, old: T?): T? =
+ tagBlock(descriptor.getTag(index)) { updateNullableSerializableValue(deserializer, old) }
private fun <E> tagBlock(tag: Tag, block: () -> E): E {
pushTag(tag)
diff --git a/runtime/commonMain/src/kotlinx/serialization/internal/Arrays.common.kt b/runtime/commonMain/src/kotlinx/serialization/internal/Arrays.common.kt
index 821af6dc..a06b2d29 100644
--- a/runtime/commonMain/src/kotlinx/serialization/internal/Arrays.common.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/internal/Arrays.common.kt
@@ -4,6 +4,12 @@
package kotlinx.serialization.internal
-// Array.get that checks indices on JS
+/**
+ * Array.get that checks indices on JS
+ */
internal expect fun <T> Array<T>.getChecked(index: Int): T
+
+/**
+ * Array.get that checks indices on JS
+ */
internal expect fun BooleanArray.getChecked(index: Int): Boolean
diff --git a/runtime/commonMain/src/kotlinx/serialization/internal/Enums.kt b/runtime/commonMain/src/kotlinx/serialization/internal/Enums.kt
index 03eeff4a..9a682e82 100644
--- a/runtime/commonMain/src/kotlinx/serialization/internal/Enums.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/internal/Enums.kt
@@ -47,7 +47,8 @@ public class EnumDescriptor(
// Used for enums that are not explicitly serializable
@InternalSerializationApi
-@Deprecated(level = DeprecationLevel.HIDDEN, message = "For plugin-generated code")
+@Deprecated(level = DeprecationLevel.ERROR, message = "For plugin-generated code, " +
+ "should not be used directly. For the custom serializers please report your use-case to project issues, so proper public API could be introduced instead")
public class EnumSerializer<T : Enum<T>>(
serialName: String,
private val values: Array<T>
diff --git a/runtime/commonMain/src/kotlinx/serialization/internal/ObjectSerializer.kt b/runtime/commonMain/src/kotlinx/serialization/internal/ObjectSerializer.kt
index 77f87c38..ff714641 100644
--- a/runtime/commonMain/src/kotlinx/serialization/internal/ObjectSerializer.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/internal/ObjectSerializer.kt
@@ -12,7 +12,11 @@ import kotlinx.serialization.*
* uses an [object instance][objectInstance].
* By default, a singleton is serialized as an empty structure, e.g. `{}` in JSON
*/
-@Deprecated("", level = DeprecationLevel.HIDDEN)
+@Deprecated(
+ "For plugin-generated code, " +
+ "should not be used directly. For the custom serializers please report your use-case to project issues, so proper public API could be introduced instead",
+ level = DeprecationLevel.ERROR
+)
public class ObjectSerializer<T : Any>(serialName: String, private val objectInstance: T) : KSerializer<T> {
override val descriptor: SerialDescriptor = SerialDescriptor(serialName, StructureKind.OBJECT)
diff --git a/runtime/commonMain/src/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.kt b/runtime/commonMain/src/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.kt
index 7937ccf6..812dc0cb 100644
--- a/runtime/commonMain/src/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.kt
@@ -27,8 +27,8 @@ public open class PluginGeneratedSerialDescriptor(
// Classes rarely have annotations, so we can save up a bit of allocations here
private var classAnnotations: MutableList<Annotation>? = null
private var flags = BooleanArray(elementsCount)
+ internal val namesSet: Set<String> get() = indices.keys
// don't change lazy mode: KT-32871, KT-32872
- internal val namesSet: Set<String> by lazy { names.toHashSet() }
private val indices: Map<String, Int> by lazy { buildIndices() }
public fun addElement(name: String, isOptional: Boolean = false) {
@@ -59,7 +59,7 @@ public open class PluginGeneratedSerialDescriptor(
override fun getElementDescriptor(index: Int): SerialDescriptor {
return generatedSerializer?.childSerializers()?.get(index)?.descriptor
- ?: error("Unexpected call to getElementDescriptor($index)")
+ ?: throw IndexOutOfBoundsException("$serialName descriptor has only $elementsCount elements, index: $index")
}
override fun isElementOptional(index: Int): Boolean = flags.getChecked(index)
diff --git a/runtime/commonMain/src/kotlinx/serialization/internal/Primitives.kt b/runtime/commonMain/src/kotlinx/serialization/internal/Primitives.kt
index 27508fc8..fa0f74e7 100644
--- a/runtime/commonMain/src/kotlinx/serialization/internal/Primitives.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/internal/Primitives.kt
@@ -69,9 +69,8 @@ private fun checkName(serialName: String) {
}
@Suppress("UNCHECKED_CAST")
-internal fun <T : Any> KClass<T>.builtinSerializerOrNull(): KSerializer<T>? {
- return BUILTIN_SERIALIZERS[this] as? KSerializer<T>
-}
+internal fun <T : Any> KClass<T>.builtinSerializerOrNull(): KSerializer<T>? =
+ BUILTIN_SERIALIZERS[this] as KSerializer<T>?
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility")
object UnitSerializer : KSerializer<Unit> {
diff --git a/runtime/commonMain/src/kotlinx/serialization/json/JsonElementSerializer.kt b/runtime/commonMain/src/kotlinx/serialization/json/JsonElementSerializer.kt
index d12ab702..0fa4bae9 100644
--- a/runtime/commonMain/src/kotlinx/serialization/json/JsonElementSerializer.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/json/JsonElementSerializer.kt
@@ -54,7 +54,7 @@ public object JsonElementSerializer : KSerializer<JsonElement> {
@Serializer(forClass = JsonPrimitive::class)
public object JsonPrimitiveSerializer : KSerializer<JsonPrimitive> {
override val descriptor: SerialDescriptor =
- SerialDescriptor("kotlinx.serialization.json.JsonPrimitive", PrimitiveKind.STRING) {}
+ SerialDescriptor("kotlinx.serialization.json.JsonPrimitive", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: JsonPrimitive) {
verify(encoder)
@@ -80,7 +80,7 @@ public object JsonPrimitiveSerializer : KSerializer<JsonPrimitive> {
public object JsonNullSerializer : KSerializer<JsonNull> {
// technically, JsonNull is an object, but it does not call beginStructure/endStructure at all
override val descriptor: SerialDescriptor =
- SerialDescriptor("kotlinx.serialization.json.JsonNull", UnionKind.ENUM_KIND) {}
+ SerialDescriptor("kotlinx.serialization.json.JsonNull", UnionKind.ENUM_KIND)
override fun serialize(encoder: Encoder, value: JsonNull) {
verify(encoder)
@@ -102,7 +102,7 @@ public object JsonNullSerializer : KSerializer<JsonNull> {
public object JsonLiteralSerializer : KSerializer<JsonLiteral> {
override val descriptor: SerialDescriptor =
- SerialDescriptor("kotlinx.serialization.json.JsonLiteral", PrimitiveKind.STRING) {}
+ PrimitiveDescriptor("kotlinx.serialization.json.JsonLiteral", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: JsonLiteral) {
verify(encoder)
diff --git a/runtime/commonMain/src/kotlinx/serialization/json/internal/TreeJsonInput.kt b/runtime/commonMain/src/kotlinx/serialization/json/internal/TreeJsonInput.kt
index a70890d6..88e2749a 100644
--- a/runtime/commonMain/src/kotlinx/serialization/json/internal/TreeJsonInput.kt
+++ b/runtime/commonMain/src/kotlinx/serialization/json/internal/TreeJsonInput.kt
@@ -7,6 +7,7 @@
package kotlinx.serialization.json.internal
import kotlinx.serialization.*
+import kotlinx.serialization.internal.*
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*
import kotlin.jvm.*
@@ -45,12 +46,12 @@ private sealed class AbstractJsonTreeInput(
override fun composeName(parentName: String, childName: String): String = childName
- override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
+ override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
val currentObject = currentObject()
- return when (desc.kind) {
+ return when (descriptor.kind) {
StructureKind.LIST, is PolymorphicKind -> JsonTreeListInput(json, cast(currentObject))
StructureKind.MAP -> json.selectMapMode(
- desc,
+ descriptor,
{ JsonTreeMapInput(json, cast(currentObject)) },
{ JsonTreeListInput(json, cast(currentObject)) }
)
@@ -58,6 +59,10 @@ private sealed class AbstractJsonTreeInput(
}
}
+ override fun endStructure(descriptor: SerialDescriptor) {
+ // Nothing
+ }
+
protected open fun getValue(tag: String): JsonPrimitive {
val currentElement = currentElement(tag)
return currentElement as? JsonPrimitive ?: throw JsonDecodingException(
@@ -124,14 +129,10 @@ private open class JsonTreeInput(json: Json, override val obj: JsonObject) : Abs
override fun currentElement(tag: String): JsonElement = obj.getValue(tag)
override fun endStructure(descriptor: SerialDescriptor) {
- if (!configuration.strictMode || descriptor.kind is PolymorphicKind.OPEN) return
+ if (!configuration.strictMode || descriptor.kind is PolymorphicKind) return
// Validate keys
- val names = HashSet<String>(descriptor.elementsCount)
- for (i in 0 until descriptor.elementsCount) {
- names += descriptor.getElementName(i)
- }
-
+ val names = descriptor.cachedSerialNames()
for (key in obj.keys) {
if (key !in names) throw jsonUnknownKeyException(-1, key)
}
diff --git a/runtime/commonTest/src/kotlinx/serialization/SerialDescriptorBuilderTest.kt b/runtime/commonTest/src/kotlinx/serialization/SerialDescriptorBuilderTest.kt
index bdbaf38d..e6ee096e 100644
--- a/runtime/commonTest/src/kotlinx/serialization/SerialDescriptorBuilderTest.kt
+++ b/runtime/commonTest/src/kotlinx/serialization/SerialDescriptorBuilderTest.kt
@@ -4,11 +4,9 @@
package kotlinx.serialization
-import kotlinx.serialization.internal.*
import kotlinx.serialization.test.*
import kotlin.test.*
-@ImplicitReflectionSerializer
class SerialDescriptorBuilderTest {
@Serializable
@@ -72,11 +70,18 @@ class SerialDescriptorBuilderTest {
@Test
fun testMisconfiguration() {
- assertFailsWith<IllegalStateException> {
- SerialDescriptor("", StructureKind.CLASS) {
+ assertFailsWith<IllegalArgumentException> {
+ SerialDescriptor("a", StructureKind.CLASS) {
element<Int>("i")
element<Int>("i")
}
}
+
+ assertFailsWith<IllegalArgumentException> { SerialDescriptor("", StructureKind.CLASS) }
+ assertFailsWith<IllegalArgumentException> { SerialDescriptor("\t", StructureKind.CLASS) }
+ assertFailsWith<IllegalArgumentException> { SerialDescriptor(" ", StructureKind.CLASS) }
+ assertFailsWith<IllegalArgumentException> { PrimitiveDescriptor("", PrimitiveKind.STRING) }
+ assertFailsWith<IllegalArgumentException> { PrimitiveDescriptor(" ", PrimitiveKind.STRING) }
+ assertFailsWith<IllegalArgumentException> { PrimitiveDescriptor("\t", PrimitiveKind.STRING) }
}
}
diff --git a/runtime/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt b/runtime/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt
index 6453d174..5bcbadca 100644
--- a/runtime/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt
+++ b/runtime/commonTest/src/kotlinx/serialization/features/GenericCustomSerializerTest.kt
@@ -32,8 +32,8 @@ class CheckedData<T : Any>(val data: T, val checkSum: ByteArray) {
@Serializer(forClass = CheckedData::class)
class CheckedDataSerializer<T : Any>(private val dataSerializer: KSerializer<T>) : KSerializer<CheckedData<T>> {
override val descriptor: SerialDescriptor = SerialDescriptor("CheckedDataSerializer") {
- val typeDescriptor = dataSerializer.descriptor
- element("data", typeDescriptor)
+ val dataDescriptor = dataSerializer.descriptor
+ element("data", dataDescriptor)
element("checkSum", ByteArraySerializer.descriptor)
}
diff --git a/runtime/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt b/runtime/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt
index 8307633c..4eaee806 100644
--- a/runtime/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt
+++ b/runtime/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionInSealedClassesTest.kt
@@ -51,6 +51,6 @@ class SerialNameCollisionInSealedClassesTest {
BaseCollision.Child()
BaseCollision.ChildCollided()
BaseCollision.ChildCollided.serializer().descriptor // Doesn't fail
- assertFailsWith<IllegalStateException> { BaseCollision.serializer().descriptor }
+ assertFailsWith<IllegalArgumentException> { BaseCollision.serializer().descriptor }
}
}