1 /*
2  * Copyright 2017-2020 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.builtins.*
9 import kotlinx.serialization.encoding.*
10 
11 /**
12  * Serial descriptor is an inherent property of [KSerializer] that describes the structure of the serializable type.
13  * The structure of the serializable type is not only the characteristic of the type itself, but also of the serializer as well,
14  * meaning that one type can have multiple descriptors that have completely different structure.
15  *
16  * For example, the class `class Color(val rgb: Int)` can have multiple serializable representations,
17  * such as `{"rgb": 255}`, `"#0000FF"`, `[0, 0, 255]` and `{"red": 0, "green": 0, "blue": 255}`.
18  * Representations are determined by serializers and each such serializer has its own descriptor that identifies
19  * each structure in a distinguishable and format-agnostic manner.
20  *
21  * ### Structure
22  * Serial descriptor is identified by its [name][serialName] and consists of kind, potentially empty set of
23  * children elements and additional metadata.
24  *
25  * * [serialName] uniquely identifies the descriptor (and the corresponding serializer) for non-generic types.
26  *   For generic types, the actual type substitution is omitted from the string representation and the name
27  *   identifies the family of the serializers without type substitutions. However, type substitution is accounted
28  *   in [equals] and [hashCode] operations, meaning that descriptors of generic classes with the same name, but different type
29  *   arguments, are not equal to each other.
30  *   [serialName] is typically used to specify the type of the target class during serialization of polymorphic and sealed
31  *   classes, for observability and diagnostics.
32  * * [Kind][SerialKind] defines what this descriptor represents: primitive, enum, object, collection etc.
33  * * Children elements are represented as serial descriptors as well and define the structure of the type's elements.
34  * * Metadata carries additional information, such as [nullability][nullable], [optionality][isElementOptional]
35  *   and [serial annotations][getElementAnnotations].
36  *
37  * ### Usages
38  * There are two general usages of the descriptors: THE serialization process and serialization introspection.
39  *
40  * #### Serialization
41  * Serial descriptor is used as a bridge between decoders/encoders and serializers.
42  * When asking for a next element, the serializer provides an expected descriptor to the decoder, and,
43  * based on the descriptor content, decoder decides how to parse its input.
44  * In JSON, for example, when the encoder is asked to encode the next element and this element
45  * is a subtype of [List], the encoder receives a descriptor with [StructureKind.LIST] and, based on that,
46  * first writes an opening square bracket before writing the content of the list.
47  *
48  * Serial descriptor _encapsulates_ the structure of the data, so serializers can be free from
49  * format-specific details. `ListSerializer` knows nothing about JSON and square brackets, providing
50  * only the structure of the data and delegating encoding decision to the format itself.
51  *
52  * #### Introspection
53  * Another usage of a serial descriptor is type introspection without its serialization.
54  * Introspection can be used to check, whether the given serializable class complies the
55  * corresponding scheme and to generate JSON or ProtoBuf schema from the given class.
56  *
57  * ### Indices
58  * Serial descriptor API operates with children indices.
59  * For the fixed-size structures, such as regular classes, index is represented by a value in
60  * the range from zero to [elementsCount] and represent and index of the property in this class.
61  * Consequently, primitives do not have children and their element count is zero.
62  *
63  * For collections and maps indices don't have fixed bound. Regular collections descriptors usually
64  * have one element (`T`, maps have two, one for keys and one for values), but potentially unlimited
65  * number of actual children values. Valid indices range is not known statically
66  * and implementations of such descriptor should provide consistent and unbounded names and indices.
67  *
68  * In practice, for regular classes it is allowed to invoke `getElement*(index)` methods
69  * with an index from `0` to [elementsCount] range and element at the particular index corresponds to the
70  * serializable property at the given position.
71  * For collections and maps, index parameter for `getElement*(index)` methods is effectively bounded
72  * by the maximal number of collection/map elements.
73  *
74  * ### Thread-safety and mutability
75  * Serial descriptor implementation should be immutable and, thus, thread-safe.
76  *
77  * ### Equality and caching
78  * Serial descriptor can be used as a unique identifier for format-specific data or schemas and
79  * this implies the following restrictions on its `equals` and `hashCode`:
80  *
81  * An [equals] implementation should use both [serialName] and elements structure.
82  * Comparing [elementDescriptors] directly is discouraged,
83  * because it may cause a stack overflow error, e.g. if a serializable class `T` contains elements of type `T`.
84  * To avoid it, a serial descriptor implementation should compare only descriptors
85  * of class' type parameters, in a way that `serializer<Box<Int>>().descriptor != serializer<Box<String>>().descriptor`.
86  * If type parameters are equal, descriptors structure should be compared by using children elements
87  * descriptors' [serialName]s, which correspond to class names
88  * (do not confuse with elements own names, which correspond to properties names); and/or other [SerialDescriptor]
89  * properties, such as [kind].
90  * An example of [equals] implementation:
91  * ```
92  * if (this === other) return true
93  * if (other::class != this::class) return false
94  * if (serialName != other.serialName) return false
95  * if (!typeParametersAreEqual(other)) return false
96  * if (this.elementDescriptors().map { it.serialName } != other.elementDescriptors().map { it.serialName }) return false
97  * return true
98  * ```
99  *
100  * [hashCode] implementation should use the same properties for computing the result.
101  *
102  * ### User-defined serial descriptors
103  * The best way to define a custom descriptor is to use [buildClassSerialDescriptor] builder function, where
104  * for each serializable property the corresponding element is declared.
105  *
106  * Example:
107  * ```
108  * // Class with custom serializer and custom serial descriptor
109  * class Data(
110  *     val intField: Int, // This field is ignored by custom serializer
111  *     val longField: Long, // This field is written as long, but in serialized form is named as "_longField"
112  *     val stringList: List<String> // This field is written as regular list of strings
113  * )
114  *
115  * // Descriptor for such class:
116  * buildClassSerialDescriptor("my.package.Data") {
117  *     // intField is deliberately ignored by serializer -- not present in the descriptor as well
118  *     element<Long>("_longField") // longField is named as _longField
119  *     element("stringField", listSerialDescriptor<String>())
120  * }
121  *
122  * // Example of 'serialize' function for such descriptor
123  * override fun serialize(encoder: Encoder, value: Data) {
124  *     encoder.encodeStructure(descriptor) {
125  *         encodeLongElement(descriptor, 0, value.longField) // Will be written as "_longField" because descriptor's child at index 0 says so
126  *         encodeSerializableElement(descriptor, 1, ListSerializer(String.serializer()), value.stringList)
127  *     }
128  * }
129  * ```
130  *
131  * For a classes that are represented as a single primitive value, [PrimitiveSerialDescriptor] builder function can be used instead.
132  *
133  * ### Consistency violations
134  * An implementation of [SerialDescriptor] should be consistent with the implementation of the corresponding [KSerializer].
135  * Yet it is not type-checked statically, thus making it possible to declare a non-consistent implementations of descriptor and serializer.
136  * In such cases, the behaviour of an underlying format is unspecified and may lead to both runtime errors and encoding of
137  * corrupted data that is impossible to decode back.
138  *
139  * ### Not stable for inheritance
140  *
141  * `SerialDescriptor` interface is not stable for inheritance in 3rd party libraries, as new methods
142  * might be added to this interface or contracts of the existing methods can be changed.
143  * This interface is safe to build using [buildClassSerialDescriptor] and [PrimitiveSerialDescriptor],
144  * and is safe to delegate implementation to existing instances.
145  */
146 public interface SerialDescriptor {
147     /**
148      * Serial name of the descriptor that identifies pair of the associated serializer and target class.
149      *
150      * For generated serializers, serial name is equal to the corresponding class's fully-qualified name
151      * or, if overridden, [SerialName].
152      * Custom serializers should provide a unique serial name that identify both the serializable class and
153      * the serializer itself, ignoring type arguments, if they are present.
154      */
155     @ExperimentalSerializationApi
156     public val serialName: String
157 
158     /**
159      * The kind of the serialized form that determines **the shape** of the serialized data.
160      * Formats use serial kind to add and parse serializer-agnostic metadata to the result.
161      *
162      * For example, JSON format wraps [classes][StructureKind.CLASS] and [StructureKind.MAP] into
163      * brackets, while ProtoBuf just serialize these types in separate ways.
164      *
165      * Kind should be consistent with the implementation, for example, if it is a [primitive][PrimitiveKind],
166      * then its elements count should be zero and vice versa.
167      */
168     @ExperimentalSerializationApi
169     public val kind: SerialKind
170 
171     /**
172      * Whether the descriptor describes nullable element.
173      * Returns `true` if associated serializer can serialize/deserialize nullable elements of the described type.
174      */
175     @ExperimentalSerializationApi
176     public val isNullable: Boolean get() = false
177 
178     /**
179      * Returns `true` if this descriptor describes a serializable value class which underlying value
180      * is serialized directly.
181      */
182     public val isInline: Boolean get() = false
183 
184     /**
185      * The number of elements this descriptor describes, besides from the class itself.
186      * [elementsCount] describes the number of **semantic** elements, not the number
187      * of actual fields/properties in the serialized form, even though they frequently match.
188      *
189      * For example, for the following class
190      * `class Complex(val real: Long, val imaginary: Long)` the corresponding descriptor
191      * and the serialized form both have two elements, while for `class IntList : ArrayList<Int>()`
192      * the corresponding descriptor has a single element (`IntDescriptor`, the type of list element),
193      * but from zero up to `Int.MAX_VALUE` values in the serialized form.
194      */
195     @ExperimentalSerializationApi
196     public val elementsCount: Int
197 
198     /**
199      * Returns serial annotations of the associated class.
200      * Serial annotations can be used to specify an additional metadata that may be used during serialization.
201      * Only annotations marked with [SerialInfo] are added to the resulting list.
202      */
203     @ExperimentalSerializationApi
204     public val annotations: List<Annotation> get() = emptyList()
205 
206     /**
207      * Returns a positional name of the child at the given [index].
208      * Positional name represents a corresponding property name in the class, associated with
209      * the current descriptor.
210      *
211      * @throws IndexOutOfBoundsException for an illegal [index] values.
212      * @throws IllegalStateException if the current descriptor does not support children elements (e.g. is a primitive)
213      */
214     @ExperimentalSerializationApi
getElementNamenull215     public fun getElementName(index: Int): String
216 
217     /**
218      * Returns an index in the children list of the given element by its name or [CompositeDecoder.UNKNOWN_NAME]
219      * if there is no such element.
220      * The resulting index, if it is not [CompositeDecoder.UNKNOWN_NAME], is guaranteed to be usable with [getElementName].
221      */
222     @ExperimentalSerializationApi
223     public fun getElementIndex(name: String): Int
224 
225     /**
226      * Returns serial annotations of the child element at the given [index].
227      * This method differs from `getElementDescriptor(index).annotations` by reporting only
228      * declaration-specific annotations:
229      * ```
230      * @Serializable
231      * @SomeSerialAnnotation
232      * class Nested(...)
233      *
234      * @Serializable
235      * class Outer(@AnotherSerialAnnotation val nested: Nested)
236      *
237      * outerDescriptor.getElementAnnotations(0) // Returns [@AnotherSerialAnnotation]
238      * outerDescriptor.getElementDescriptor(0).annotations // Returns [@SomeSerialAnnotation]
239      * ```
240      * Only annotations marked with [SerialInfo] are added to the resulting list.
241      *
242      * @throws IndexOutOfBoundsException for an illegal [index] values.
243      * @throws IllegalStateException if the current descriptor does not support children elements (e.g. is a primitive).
244      */
245     @ExperimentalSerializationApi
246     public fun getElementAnnotations(index: Int): List<Annotation>
247 
248     /**
249      * Retrieves the descriptor of the child element for the given [index].
250      * For the property of type `T` on the position `i`, `getElementDescriptor(i)` yields the same result
251      * as for `T.serializer().descriptor`, if the serializer for this property is not explicitly overridden
252      * with `@Serializable(with = ...`)`, [Polymorphic] or [Contextual].
253      * This method can be used to completely introspect the type that the current descriptor describes.
254      *
255      * @throws IndexOutOfBoundsException for illegal [index] values.
256      * @throws IllegalStateException if the current descriptor does not support children elements (e.g. is a primitive).
257      */
258     @ExperimentalSerializationApi
259     public fun getElementDescriptor(index: Int): SerialDescriptor
260 
261     /**
262      * Whether the element at the given [index] is optional (can be absent in serialized form).
263      * For generated descriptors, all elements that have a corresponding default parameter value are
264      * marked as optional. Custom serializers can treat optional values in a serialization-specific manner
265      * without default parameters constraint.
266      *
267      * Example of optionality:
268      * ```
269      * @Serializable
270      * class Holder(
271      *     val a: Int, // Optional == false
272      *     val b: Int?, // Optional == false
273      *     val c: Int? = null, // Optional == true
274      *     val d: List<Int>, // Optional == false
275      *     val e: List<Int> = listOf(1), // Optional == true
276      * )
277      * ```
278      * Returns `false` for valid indices of collections, maps and enums.
279      *
280      * @throws IndexOutOfBoundsException for an illegal [index] values.
281      * @throws IllegalStateException if the current descriptor does not support children elements (e.g. is a primitive).
282      */
283     @ExperimentalSerializationApi
284     public fun isElementOptional(index: Int): Boolean
285 }
286 
287 /**
288  * Returns an iterable of all descriptor [elements][SerialDescriptor.getElementDescriptor].
289  */
290 @ExperimentalSerializationApi
291 public val SerialDescriptor.elementDescriptors: Iterable<SerialDescriptor>
292     get() = Iterable {
293         object : Iterator<SerialDescriptor> {
294             private var elementsLeft = elementsCount
295             override fun hasNext(): Boolean = elementsLeft > 0
296 
297             override fun next(): SerialDescriptor {
298                 return getElementDescriptor(elementsCount - (elementsLeft--))
299             }
300         }
301     }
302 
303 /**
304  * Returns an iterable of all descriptor [element names][SerialDescriptor.getElementName].
305  */
306 @ExperimentalSerializationApi
307 public val SerialDescriptor.elementNames: Iterable<String>
<lambda>null308     get() = Iterable {
309         object : Iterator<String> {
310             private var elementsLeft = elementsCount
311             override fun hasNext(): Boolean = elementsLeft > 0
312 
313             override fun next(): String {
314                 return getElementName(elementsCount - (elementsLeft--))
315             }
316         }
317     }
318