• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.encoding
6 
7 import kotlinx.serialization.*
8 import kotlinx.serialization.builtins.*
9 import kotlinx.serialization.descriptors.*
10 import kotlinx.serialization.modules.*
11 
12 /**
13  * Encoder is a core serialization primitive that encapsulates the knowledge of the underlying
14  * format and its storage, exposing only structural methods to the serializer, making it completely
15  * format-agnostic. Serialization process transforms a single value into the sequence of its
16  * primitive elements, also called its serial form, while encoding transforms these primitive elements into an actual
17  * format representation: JSON string, ProtoBuf ByteArray, in-memory map representation etc.
18  *
19  * Encoder provides high-level API that operates with basic primitive types, collections
20  * and nested structures. Internally, encoder represents output storage and operates with its state
21  * and lower level format-specific details.
22  *
23  * To be more specific, serialization transforms a value into a sequence of "here is an int, here is
24  * a double, here a list of strings and here is another object that is a nested int", while encoding
25  * transforms this sequence into a format-specific commands such as "insert opening curly bracket
26  * for a nested object start, insert a name of the value, and the value separated with colon for an int etc."
27  *
28  * The symmetric interface for the deserialization process is [Decoder].
29  *
30  * ### Serialization. Primitives
31  *
32  * If a class is represented as a single [primitive][PrimitiveKind] value in its serialized form,
33  * then one of the `encode*` methods (e.g. [encodeInt]) can be used directly.
34  *
35  * ### Serialization. Structured types.
36  *
37  * If a class is represented as a structure or has multiple values in its serialized form,
38  * `encode*` methods are not that helpful, because they do not allow working with collection types or establish structure boundaries.
39  * All these capabilities are delegated to the [CompositeEncoder] interface with a more specific API surface.
40  * To denote a structure start, [beginStructure] should be used.
41  * ```
42  * // Denote the structure start,
43  * val composite = encoder.beginStructure(descriptor)
44  * // Encoding all elements within the structure using 'composite'
45  * ...
46  * // Denote the structure end
47  * composite.endStructure(descriptor)
48  * ```
49  *
50  * E.g. if the encoder belongs to JSON format, then [beginStructure] will write an opening bracket
51  * (`{` or `[`, depending on the descriptor kind), returning the [CompositeEncoder] that is aware of colon separator,
52  * that should be appended between each key-value pair, whilst [CompositeEncoder.endStructure] will write a closing bracket.
53  *
54  * ### Exception guarantees.
55  * For the regular exceptions, such as invalid input, conflicting serial names,
56  * [SerializationException] can be thrown by any encoder methods.
57  * It is recommended to declare a format-specific subclass of [SerializationException] and throw it.
58  *
59  * ### Format encapsulation
60  *
61  * For example, for the following serializer:
62  * ```
63  * class StringHolder(val stringValue: String)
64  *
65  * object StringPairDeserializer : SerializationStrategy<StringHolder> {
66  *    override val descriptor = ...
67  *
68  *    override fun serializer(encoder: Encoder, value: StringHolder) {
69  *        // Denotes start of the structure, StringHolder is not a "plain" data type
70  *        val composite = encoder.beginStructure(descriptor)
71  *        // Encode the nested string value
72  *        composite.encodeStringElement(descriptor, index = 0)
73  *        // Denotes end of the structure
74  *        composite.endStructure(descriptor)
75  *    }
76  * }
77  * ```
78  *
79  * This serializer does not know anything about the underlying storage and will work with any properly-implemented encoder.
80  * JSON, for example, writes an opening bracket `{` during the `beginStructure` call, writes 'stringValue` key along
81  * with its value in `encodeStringElement` and writes the closing bracket `}` during the `endStructure`.
82  * XML would do roughly the same, but with different separators and structures, while ProtoBuf
83  * machinery could be completely different.
84  * In any case, all these parsing details are encapsulated by an encoder.
85  *
86  * ### Exception safety
87  *
88  * In general, catching [SerializationException] from any of `encode*` methods is not allowed and produces unspecified behaviour.
89  * After thrown exception, current encoder is left in an arbitrary state, no longer suitable for further encoding.
90  *
91  * ### Encoder implementation.
92  *
93  * While being strictly typed, an underlying format can transform actual types in the way it wants.
94  * For example, a format can support only string types and encode/decode all primitives in a string form:
95  * ```
96  * StringFormatEncoder : Encoder {
97  *
98  *     ...
99  *     override fun encodeDouble(value: Double) = encodeString(value.toString())
100  *     override fun encodeInt(value: Int) = encodeString(value.toString())
101  *     ...
102  * }
103  * ```
104  *
105  * ### Not stable for inheritance
106  *
107  * `Encoder` interface is not stable for inheritance in 3rd party libraries, as new methods
108  * might be added to this interface or contracts of the existing methods can be changed.
109  */
110 public interface Encoder {
111     /**
112      * Context of the current serialization process, including contextual and polymorphic serialization and,
113      * potentially, a format-specific configuration.
114      */
115     public val serializersModule: SerializersModule
116 
117     /**
118      * Notifies the encoder that value of a nullable type that is
119      * being serialized is not null. It should be called before writing a non-null value
120      * of nullable type:
121      * ```
122      * // Could be String? serialize method
123      * if (value != null) {
124      *     encoder.encodeNotNullMark()
125      *     encoder.encodeStringValue(value)
126      * } else {
127      *     encoder.encodeNull()
128      * }
129      * ```
130      *
131      * This method has a use in highly-performant binary formats and can
132      * be safely ignore by most of the regular formats.
133      */
134     @ExperimentalSerializationApi
135     public fun encodeNotNullMark() {}
136 
137     /**
138      * Encodes `null` value.
139      */
140     @ExperimentalSerializationApi
141     public fun encodeNull()
142 
143     /**
144      * Encodes a boolean value.
145      * Corresponding kind is [PrimitiveKind.BOOLEAN].
146      */
147     public fun encodeBoolean(value: Boolean)
148 
149     /**
150      * Encodes a single byte value.
151      * Corresponding kind is [PrimitiveKind.BYTE].
152      */
153     public fun encodeByte(value: Byte)
154 
155     /**
156      * Encodes a 16-bit short value.
157      * Corresponding kind is [PrimitiveKind.SHORT].
158      */
159     public fun encodeShort(value: Short)
160 
161     /**
162      * Encodes a 16-bit unicode character value.
163      * Corresponding kind is [PrimitiveKind.CHAR].
164      */
165     public fun encodeChar(value: Char)
166 
167     /**
168      * Encodes a 32-bit integer value.
169      * Corresponding kind is [PrimitiveKind.INT].
170      */
171     public fun encodeInt(value: Int)
172 
173     /**
174      * Encodes a 64-bit integer value.
175      * Corresponding kind is [PrimitiveKind.LONG].
176      */
177     public fun encodeLong(value: Long)
178 
179     /**
180      * Encodes a 32-bit IEEE 754 floating point value.
181      * Corresponding kind is [PrimitiveKind.FLOAT].
182      */
183     public fun encodeFloat(value: Float)
184 
185     /**
186      * Encodes a 64-bit IEEE 754 floating point value.
187      * Corresponding kind is [PrimitiveKind.DOUBLE].
188      */
189     public fun encodeDouble(value: Double)
190 
191     /**
192      * Encodes a string value.
193      * Corresponding kind is [PrimitiveKind.STRING].
194      */
195     public fun encodeString(value: String)
196 
197     /**
198      * Encodes a enum value that is stored at the [index] in [enumDescriptor] elements collection.
199      * Corresponding kind is [SerialKind.ENUM].
200      *
201      * E.g. for the enum `enum class Letters { A, B, C, D }` and
202      * serializable value "C", [encodeEnum] method should be called with `2` as am index.
203      *
204      * This method does not imply any restrictions on the output format,
205      * the format is free to store the enum by its name, index, ordinal or any other
206      */
207     public fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int)
208 
209     /**
210      * Returns [Encoder] for encoding an underlying type of a value class in an inline manner.
211      * [descriptor] describes a serializable value class.
212      *
213      * Namely, for the `@Serializable @JvmInline value class MyInt(val my: Int)`,
214      * the following sequence is used:
215      * ```
216      * thisEncoder.encodeInline(MyInt.serializer().descriptor).encodeInt(my)
217      * ```
218      *
219      * Current encoder may return any other instance of [Encoder] class, depending on the provided [descriptor].
220      * For example, when this function is called on Json encoder with `UInt.serializer().descriptor`, the returned encoder is able
221      * to encode unsigned integers.
222      *
223      * Note that this function returns [Encoder] instead of the [CompositeEncoder]
224      * because value classes always have the single property.
225      * Calling [Encoder.beginStructure] on returned instance leads to an unspecified behavior and, in general, is prohibited.
226      */
227     public fun encodeInline(descriptor: SerialDescriptor): Encoder
228 
229     /**
230      * Encodes the beginning of the nested structure in a serialized form
231      * and returns [CompositeDecoder] responsible for encoding this very structure.
232      * E.g the hierarchy:
233      * ```
234      * class StringHolder(val stringValue: String)
235      * class Holder(val stringHolder: StringHolder)
236      * ```
237      *
238      * with the following serialized form in JSON:
239      * ```
240      * {
241      *   "stringHolder" : { "stringValue": "value" }
242      * }
243      * ```
244      *
245      * will be roughly represented as the following sequence of calls:
246      * ```
247      * // Holder serializer
248      * fun serialize(encoder: Encoder, value: Holder) {
249      *     val composite = encoder.beginStructure(descriptor) // the very first opening bracket '{'
250      *     composite.encodeSerializableElement(descriptor, 0, value.stringHolder) // Serialize nested StringHolder
251      *     composite.endStructure(descriptor) // The very last closing bracket
252      * }
253      *
254      * // StringHolder serializer
255      * fun serialize(encoder: Encoder, value: StringHolder) {
256      *     val composite = encoder.beginStructure(descriptor) // One more '{' when the key "stringHolder" is already written
257      *     composite.encodeStringElement(descriptor, 0, value.stringValue) // Serialize actual value
258      *     composite.endStructure(descriptor) // Closing bracket
259      * }
260      * ```
261      */
262     public fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder
263 
264     /**
265      * Encodes the beginning of the collection with size [collectionSize] and the given serializer of its type parameters.
266      * This method has to be implemented only if you need to know collection size in advance, otherwise, [beginStructure] can be used.
267      */
268     public fun beginCollection(
269         descriptor: SerialDescriptor,
270         collectionSize: Int
271     ): CompositeEncoder = beginStructure(descriptor)
272 
273     /**
274      * Encodes the [value] of type [T] by delegating the encoding process to the given [serializer].
275      * For example, `encodeInt` call is equivalent to delegating integer encoding to [Int.serializer][Int.Companion.serializer]:
276      * `encodeSerializableValue(Int.serializer())`
277      */
278     public fun <T : Any?> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
279         serializer.serialize(this, value)
280     }
281 
282     /**
283      * Encodes the nullable [value] of type [T] by delegating the encoding process to the given [serializer].
284      */
285     @Suppress("UNCHECKED_CAST")
286     @ExperimentalSerializationApi
287     public fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) {
288         val isNullabilitySupported = serializer.descriptor.isNullable
289         if (isNullabilitySupported) {
290             // Instead of `serializer.serialize` to be able to intercept this
291             return encodeSerializableValue(serializer as SerializationStrategy<T?>, value)
292         }
293 
294         // Else default path used to avoid allocation of NullableSerializer
295         if (value == null) {
296             encodeNull()
297         } else {
298             encodeNotNullMark()
299             encodeSerializableValue(serializer, value)
300         }
301     }
302 }
303 
304 /**
305  * [CompositeEncoder] is a part of encoding process that is bound to a particular structured part of
306  * the serialized form, described by the serial descriptor passed to [Encoder.beginStructure].
307  *
308  * All `encode*` methods have `index` and `serialDescriptor` parameters with a strict semantics and constraints:
309  *   * `descriptor` is always the same as one used in [Encoder.beginStructure]. While this parameter may seem redundant,
310  *      it is required for efficient serialization process to avoid excessive field spilling.
311  *      If you are writing your own format, you can safely ignore this parameter and use one used in `beginStructure`
312  *      for simplicity.
313  *   * `index` of the element being encoded. This element at this index in the descriptor should be associated with
314  *      the one being written.
315  *
316  * The symmetric interface for the deserialization process is [CompositeDecoder].
317  *
318  * ### Not stable for inheritance
319  *
320  * `CompositeEncoder` interface is not stable for inheritance in 3rd party libraries, as new methods
321  * might be added to this interface or contracts of the existing methods can be changed.
322  */
323 public interface CompositeEncoder {
324     /**
325      * Context of the current serialization process, including contextual and polymorphic serialization and,
326      * potentially, a format-specific configuration.
327      */
328     public val serializersModule: SerializersModule
329 
330     /**
331      * Denotes the end of the structure associated with current encoder.
332      * For example, composite encoder of JSON format will write
333      * a closing bracket in the underlying input and reduce the number of nesting for pretty printing.
334      */
endStructurenull335     public fun endStructure(descriptor: SerialDescriptor)
336 
337     /**
338      * Whether the format should encode values that are equal to the default values.
339      * This method is used by plugin-generated serializers for properties with default values:
340      * ```
341      * @Serializable
342      * class WithDefault(val int: Int = 42)
343      * // serialize method
344      * if (value.int != 42 || output.shouldEncodeElementDefault(serialDesc, 0)) {
345      *    encoder.encodeIntElement(serialDesc, 0, value.int);
346      * }
347      * ```
348      *
349      * This method is never invoked for properties annotated with [EncodeDefault].
350      */
351     @ExperimentalSerializationApi
352     public fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean = true
353 
354     /**
355      * Encodes a boolean [value] associated with an element at the given [index] in [serial descriptor][descriptor].
356      * The element at the given [index] should have [PrimitiveKind.BOOLEAN] kind.
357      */
358     public fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean)
359 
360     /**
361      * Encodes a single byte [value] associated with an element at the given [index] in [serial descriptor][descriptor].
362      * The element at the given [index] should have [PrimitiveKind.BYTE] kind.
363      */
364     public fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte)
365 
366     /**
367      * Encodes a 16-bit short [value] associated with an element at the given [index] in [serial descriptor][descriptor].
368      * The element at the given [index] should have [PrimitiveKind.SHORT] kind.
369      */
370     public fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short)
371 
372     /**
373      * Encodes a 16-bit unicode character [value] associated with an element at the given [index] in [serial descriptor][descriptor].
374      * The element at the given [index] should have [PrimitiveKind.CHAR] kind.
375      */
376     public fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char)
377 
378     /**
379      * Encodes a 32-bit integer [value] associated with an element at the given [index] in [serial descriptor][descriptor].
380      * The element at the given [index] should have [PrimitiveKind.INT] kind.
381      */
382     public fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int)
383 
384     /**
385      * Encodes a 64-bit integer [value] associated with an element at the given [index] in [serial descriptor][descriptor].
386      * The element at the given [index] should have [PrimitiveKind.LONG] kind.
387      */
388     public fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long)
389 
390     /**
391      * Encodes a 32-bit IEEE 754 floating point [value] associated with an element
392      * at the given [index] in [serial descriptor][descriptor].
393      * The element at the given [index] should have [PrimitiveKind.FLOAT] kind.
394      */
395     public fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float)
396 
397     /**
398      * Encodes a 64-bit IEEE 754 floating point [value] associated with an element
399      * at the given [index] in [serial descriptor][descriptor].
400      * The element at the given [index] should have [PrimitiveKind.DOUBLE] kind.
401      */
402     public fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double)
403 
404     /**
405      * Encodes a string [value] associated with an element at the given [index] in [serial descriptor][descriptor].
406      * The element at the given [index] should have [PrimitiveKind.STRING] kind.
407      */
408     public fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String)
409 
410     /**
411      * Returns [Encoder] for decoding an underlying type of a value class in an inline manner.
412      * Serializable value class is described by the [child descriptor][SerialDescriptor.getElementDescriptor]
413      * of given [descriptor] at [index].
414      *
415      * Namely, for the `@Serializable @JvmInline value class MyInt(val my: Int)`,
416      * and `@Serializable class MyData(val myInt: MyInt)` the following sequence is used:
417      * ```
418      * thisEncoder.encodeInlineElement(MyData.serializer.descriptor, 0).encodeInt(my)
419      * ```
420      *
421      * This method provides an opportunity for the optimization to avoid boxing of a carried value
422      * and its invocation should be equivalent to the following:
423      * ```
424      * thisEncoder.encodeSerializableElement(MyData.serializer.descriptor, 0, MyInt.serializer(), myInt)
425      * ```
426      *
427      * Current encoder may return any other instance of [Encoder] class, depending on provided descriptor.
428      * For example, when this function is called on Json encoder with descriptor that has
429      * `UInt.serializer().descriptor` at the given [index], the returned encoder is able
430      * to encode unsigned integers.
431      *
432      * Note that this function returns [Encoder] instead of the [CompositeEncoder]
433      * because value classes always have the single property.
434      * Calling [Encoder.beginStructure] on returned instance leads to an unspecified behavior and, in general, is prohibited.
435      *
436      * @see Encoder.encodeInline
437      * @see SerialDescriptor.getElementDescriptor
438      */
439     public fun encodeInlineElement(
440         descriptor: SerialDescriptor,
441         index: Int
442     ): Encoder
443 
444     /**
445      * Delegates [value] encoding of the type [T] to the given [serializer].
446      * [value] is associated with an element at the given [index] in [serial descriptor][descriptor].
447      */
448     public fun <T : Any?> encodeSerializableElement(
449         descriptor: SerialDescriptor,
450         index: Int,
451         serializer: SerializationStrategy<T>,
452         value: T
453     )
454 
455     /**
456      * Delegates nullable [value] encoding of the type [T] to the given [serializer].
457      * [value] is associated with an element at the given [index] in [serial descriptor][descriptor].
458      */
459     @ExperimentalSerializationApi
460     public fun <T : Any> encodeNullableSerializableElement(
461         descriptor: SerialDescriptor,
462         index: Int,
463         serializer: SerializationStrategy<T>,
464         value: T?
465     )
466 }
467 
468 /**
469  * Begins a structure, encodes it using the given [block] and ends it.
470  */
471 public inline fun Encoder.encodeStructure(
472     descriptor: SerialDescriptor,
473     crossinline block: CompositeEncoder.() -> Unit
474 ) {
475     val composite = beginStructure(descriptor)
476     composite.block()
477     composite.endStructure(descriptor)
478 }
479 
480 /**
481  * Begins a collection, encodes it using the given [block] and ends it.
482  */
encodeCollectionnull483 public inline fun Encoder.encodeCollection(
484     descriptor: SerialDescriptor,
485     collectionSize: Int,
486     crossinline block: CompositeEncoder.() -> Unit
487 ) {
488     val composite = beginCollection(descriptor, collectionSize)
489     composite.block()
490     composite.endStructure(descriptor)
491 }
492 
493 /**
494  * Begins a collection, calls [block] with each item and ends the collections.
495  */
encodeCollectionnull496 public inline fun <E> Encoder.encodeCollection(
497     descriptor: SerialDescriptor,
498     collection: Collection<E>,
499     crossinline block: CompositeEncoder.(index: Int, E) -> Unit
500 ) {
501     encodeCollection(descriptor, collection.size) {
502         collection.forEachIndexed { index, e ->
503             block(index, e)
504         }
505     }
506 }
507