1 /* 2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization.descriptors 6 7 import kotlinx.serialization.* 8 import kotlinx.serialization.encoding.* 9 import kotlinx.serialization.modules.* 10 11 /** 12 * Serial kind is an intrinsic property of [SerialDescriptor] that indicates how 13 * the corresponding type is structurally represented by its serializer. 14 * 15 * Kind is used by serialization formats to determine how exactly the given type 16 * should be serialized. For example, JSON format detects the kind of the value and, 17 * depending on that, may write it as a plain value for primitive kinds, open a 18 * curly brace '{' for class-like structures and square bracket '[' for list- and array- like structures. 19 * 20 * Kinds are used both during serialization, to serialize a value properly and statically, and 21 * to introspect the type structure or build serialization schema. 22 * 23 * Kind should match the structure of the serialized form, not the structure of the corresponding Kotlin class. 24 * Meaning that if serializable class `class IntPair(val left: Int, val right: Int)` is represented by the serializer 25 * as a single `Long` value, its descriptor should have [PrimitiveKind.LONG] without nested elements even though the class itself 26 * represents a structure with two primitive fields. 27 */ 28 @ExperimentalSerializationApi 29 public sealed class SerialKind { 30 31 /** 32 * Represents a Kotlin [Enum] with statically known values. 33 * All enum values should be enumerated in descriptor elements. 34 * Each element descriptor of a [Enum] kind represents an instance of a particular enum 35 * and has an [StructureKind.OBJECT] kind. 36 * Each [positional name][SerialDescriptor.getElementName] contains a corresponding enum element [name][Enum.name]. 37 * 38 * Corresponding encoder and decoder methods are [Encoder.encodeEnum] and [Decoder.decodeEnum]. 39 */ 40 @ExperimentalSerializationApi 41 public object ENUM : SerialKind() 42 43 /** 44 * Represents an "unknown" type that will be known only at the moment of the serialization. 45 * Effectively it defers the choice of the serializer to a moment of the serialization, and can 46 * be used for [contextual][Contextual] serialization. 47 * 48 * To introspect descriptor of this kind, an instance of [SerializersModule] is required. 49 * See [capturedKClass] extension property for more details. 50 * However, if possible options are known statically (e.g. for sealed classes), they can be 51 * enumerated in child descriptors similarly to [ENUM]. 52 */ 53 @ExperimentalSerializationApi 54 public object CONTEXTUAL : SerialKind() 55 toStringnull56 override fun toString(): String { 57 // KNPE should never happen, because SerialKind is sealed and all inheritors are non-anonymous 58 return this::class.simpleName!! 59 } 60 61 // Provide a stable hashcode for objects hashCodenull62 override fun hashCode(): Int = toString().hashCode() 63 } 64 65 /** 66 * Values of primitive kinds usually are represented as a single value. 67 * All default serializers for Kotlin [primitives types](https://kotlinlang.org/docs/tutorials/kotlin-for-py/primitive-data-types-and-their-limitations.html) 68 * and [String] have primitive kind. 69 * 70 * ### Serializers interaction 71 * 72 * Serialization formats typically handle these kinds by calling a corresponding primitive method on encoder or decoder. 73 * For example, if the following serializable class `class Color(val red: Byte, val green: Byte, val blue: Byte)` is represented by your serializer 74 * as a single [Int] value, a typical serializer will serialize its value in the following manner: 75 * ``` 76 * val intValue = color.rgbToInt() 77 * encoder.encodeInt(intValue) 78 * ``` 79 * and a corresponding [Decoder] counterpart. 80 * 81 * ### Implementation note 82 * 83 * Serial descriptors for primitive kinds are not expected to have any nested elements, thus its element count should be zero. 84 * If a class is represented as a primitive value, its corresponding serial name *should not* be equal to the corresponding primitive type name. 85 * For the `Color` example, represented as single [Int], its descriptor should have [INT] kind, zero elements and serial name **not equals** 86 * to `kotlin.Int`: `PrimitiveDescriptor("my.package.ColorAsInt", PrimitiveKind.INT)` 87 */ 88 @OptIn(ExperimentalSerializationApi::class) // May be @Experimental, but break clients + makes impossible to use stable PrimitiveSerialDescriptor 89 public sealed class PrimitiveKind : SerialKind() { 90 /** 91 * Primitive kind that represents a boolean `true`/`false` value. 92 * Corresponding Kotlin primitive is [Boolean]. 93 * Corresponding encoder and decoder methods are [Encoder.encodeBoolean] and [Decoder.decodeBoolean]. 94 */ 95 public object BOOLEAN : PrimitiveKind() 96 97 /** 98 * Primitive kind that represents a single byte value. 99 * Corresponding Kotlin primitive is [Byte]. 100 * Corresponding encoder and decoder methods are [Encoder.encodeByte] and [Decoder.decodeByte]. 101 */ 102 public object BYTE : PrimitiveKind() 103 104 /** 105 * Primitive kind that represents a 16-bit unicode character value. 106 * Corresponding Kotlin primitive is [Char]. 107 * Corresponding encoder and decoder methods are [Encoder.encodeChar] and [Decoder.decodeChar]. 108 */ 109 public object CHAR : PrimitiveKind() 110 111 /** 112 * Primitive kind that represents a 16-bit short value. 113 * Corresponding Kotlin primitive is [Short]. 114 * Corresponding encoder and decoder methods are [Encoder.encodeShort] and [Decoder.decodeShort]. 115 */ 116 public object SHORT : PrimitiveKind() 117 118 /** 119 * Primitive kind that represents a 32-bit int value. 120 * Corresponding Kotlin primitive is [Int]. 121 * Corresponding encoder and decoder methods are [Encoder.encodeInt] and [Decoder.decodeInt]. 122 */ 123 public object INT : PrimitiveKind() 124 125 /** 126 * Primitive kind that represents a 64-bit long value. 127 * Corresponding Kotlin primitive is [Long]. 128 * Corresponding encoder and decoder methods are [Encoder.encodeLong] and [Decoder.decodeLong]. 129 */ 130 public object LONG : PrimitiveKind() 131 132 /** 133 * Primitive kind that represents a 32-bit IEEE 754 floating point value. 134 * Corresponding Kotlin primitive is [Float]. 135 * Corresponding encoder and decoder methods are [Encoder.encodeFloat] and [Decoder.decodeFloat]. 136 */ 137 public object FLOAT : PrimitiveKind() 138 139 /** 140 * Primitive kind that represents a 64-bit IEEE 754 floating point value. 141 * Corresponding Kotlin primitive is [Double]. 142 * Corresponding encoder and decoder methods are [Encoder.encodeDouble] and [Decoder.decodeDouble]. 143 */ 144 public object DOUBLE : PrimitiveKind() 145 146 /** 147 * Primitive kind that represents a string value. 148 * Corresponding Kotlin primitive is [String]. 149 * Corresponding encoder and decoder methods are [Encoder.encodeString] and [Decoder.decodeString]. 150 */ 151 public object STRING : PrimitiveKind() 152 } 153 154 /** 155 * Structure kind represents values with composite structure of nested elements of depth and arbitrary number. 156 * We acknowledge following structured kinds: 157 * 158 * ### Regular classes 159 * The most common case for serialization, that represents an arbitrary structure with fixed count of elements. 160 * When the regular Kotlin class is marked as [Serializable], its descriptor kind will be [CLASS]. 161 * 162 * ### Lists 163 * [LIST] represent a structure with potentially unknown in advance number of elements of the same type. 164 * All standard serializable [List] implementors and arrays are represented as [LIST] kind of the same type. 165 * 166 * ### Maps 167 * [MAP] represent a structure with potentially unknown in advance number of key-value pairs of the same type. 168 * All standard serializable [Map] implementors are represented as [Map] kind of the same type. 169 * 170 * ### Kotlin objects 171 * A singleton object defined with `object` keyword with an [OBJECT] kind. 172 * By default, objects are serialized as empty structures without any states and their identity is preserved 173 * across serialization within the same process, so you always have the same instance of the object. 174 * 175 * ### Serializers interaction 176 * Serialization formats typically handle these kinds by marking structure start and end. 177 * E.g. the following serializable class `class IntHolder(myValue: Int)` of structure kind [CLASS] is handled by 178 * serializer as the following call sequence: 179 * ``` 180 * val composite = encoder.beginStructure(descriptor) // Denotes the start of the structure 181 * composite.encodeIntElement(descriptor, index = 0, holder.myValue) 182 * composite.endStructure(descriptor) // Denotes the end of the structure 183 * ``` 184 * and its corresponding [Decoder] counterpart. 185 * 186 * ### Serial descriptor implementors note 187 * These kinds can be used not only for collection and regular classes. 188 * For example, provided serializer for [Map.Entry] represents it as [Map] type, so it is serialized 189 * as `{"actualKey": "actualValue"}` map directly instead of `{"key": "actualKey", "value": "actualValue"}` 190 */ 191 @ExperimentalSerializationApi 192 public sealed class StructureKind : SerialKind() { 193 194 /** 195 * Structure kind for regular classes with an arbitrary, but known statically, structure. 196 * Serializers typically encode classes with calls to [Encoder.beginStructure] and [CompositeEncoder.endStructure], 197 * writing the elements of the class between these calls. 198 */ 199 public object CLASS : StructureKind() 200 201 /** 202 * Structure kind for lists and arrays of an arbitrary length. 203 * Serializers typically encode classes with calls to [Encoder.beginCollection] and [CompositeEncoder.endStructure], 204 * writing the elements of the list between these calls. 205 * Built-in list serializers treat elements as homogeneous, though application-specific serializers may impose 206 * application-specific restrictions on specific [LIST] types. 207 * 208 * Example of such application-specific serialization may be class `class ListOfThreeElements() : List<Any>`, 209 * for which an author of the serializer knows that while it is `List<Any>`, in fact, is always has three elements 210 * of a known type (e.g. the first is always a string, the second one is always an int etc.) 211 */ 212 public object LIST : StructureKind() 213 214 /** 215 * Structure kind for maps of an arbitrary length. 216 * Serializers typically encode classes with calls to [Encoder.beginCollection] and [CompositeEncoder.endStructure], 217 * writing the elements of the map between these calls. 218 * 219 * Built-in map serializers treat elements as homogeneous, though application-specific serializers may impose 220 * application-specific restrictions on specific [MAP] types. 221 */ 222 public object MAP : StructureKind() 223 224 /** 225 * Structure kind for singleton objects defined with `object` keyword. 226 * By default, objects are serialized as empty structures without any state and their identity is preserved 227 * across serialization within the same process, so you always have the same instance of the object. 228 * 229 * Empty structure is represented as a call to [Encoder.beginStructure] with the following [CompositeEncoder.endStructure] 230 * without any intermediate encodings. 231 */ 232 public object OBJECT : StructureKind() 233 } 234 235 /** 236 * Polymorphic kind represents a (bounded) polymorphic value, that is referred 237 * by some base class or interface, but its structure is defined by one of the possible implementations. 238 * Polymorphic kind is, by its definition, a union kind and is extracted to its own subtype to emphasize 239 * bounded and sealed polymorphism common property: not knowing the actual type statically and requiring 240 * formats to additionally encode it. 241 */ 242 @ExperimentalSerializationApi 243 public sealed class PolymorphicKind : SerialKind() { 244 /** 245 * Sealed kind represents Kotlin sealed classes, where all subclasses are known statically at the moment of declaration. 246 * [SealedClassSerializer] can be used as an example of sealed serialization. 247 */ 248 public object SEALED : PolymorphicKind() 249 250 /** 251 * Open polymorphic kind represents statically unknown type that is hidden behind a given base class or interface. 252 * [PolymorphicSerializer] can be used as an example of polymorphic serialization. 253 * 254 * Due to security concerns and typical mistakes that arises from polymorphic serialization, by default 255 * `kotlinx.serialization` provides only bounded polymorphic serialization, forcing users to register all possible 256 * serializers for a given base class or interface. 257 * 258 * To introspect descriptor of this kind (e.g. list possible subclasses), an instance of [SerializersModule] is required. 259 * See [capturedKClass] extension property for more details. 260 */ 261 public object OPEN : PolymorphicKind() 262 } 263